Я думаю, что есть опция, которую вы не включили (которую я бы использовал для кода, критичного к производительности), то есть для создания кортежа функциональных объектов и «итерации» по такому кортежу.К сожалению, нет хорошего API для итерации по кортежу, поэтому нужно реализовать свой собственный.См. Фрагмент ниже
#include <tuple>
#include <functional>
template<int ... Id, typename Functions>
auto apply(std::integer_sequence<int, Id ...>, Functions& my_functions, double& v, double a, double b){
([](auto a, auto b){a=b;}(v, std::get<Id>(my_functions)( a, b )), ...);
}
int main(){
auto fA = [](double a, double b){return a*b;};
auto fB = [](double a, double b){return a+b;};
//create the tuple
auto my_functions=std::make_tuple(fA, fB);
double v=0;
double a = 1.;
double b = 1.;
//iterate over the tuple
apply(std::make_integer_sequence<int, 2>(), my_functions, v, a, b);
}
Таким образом, вы создаете абстракцию с нулевыми издержками для безопасного типа, поскольку компилятор знает все о используемых вами типах (вам не нужен механизм стирания типов).Также нет необходимости в виртуальных функциях (как в CRTP), так что компилятор, вероятно, встроит вызовы функций.В приведенном выше фрагменте используются общие лямбда-выражения C ++ 17, которые также могут быть реализованы в соответствии с C ++ 14 или C ++ 11, но они будут более многословными.Я бы предпочел это, а не CRTP, потому что для меня это выглядит более читабельно: нет статического приведения к производному классу и нет искусственной иерархии наследования.
РЕДАКТИРОВАТЬ: из вашего ответа похоже, что вам на самом деле не нужен CRTPздесь то, что вы пишете с использованием решения CRTP, эквивалентно этому
enum ftype { A = 0, B, C };
auto fA = [](double a, double b){return a*b;};
auto fB = [](double a, double b){return a+b;};
int main(){
std::vector<ftype> types(2);
types[0]=A;
types[1]=B;
auto value = [&types](double a, double b, ftype i){
switch(i){
case (ftype::A):
return fA(a,b);
break;
case (ftype::B):
return fB(a,b);
break;
}
};
double v=value(1., 1., A);
v=value(1., 1., B);
}
Может быть, дело вкуса, но я думаю, что приведенная выше версия более читабельна (вам не нужен общий базовый класс,или статическое приведение к производному классу).