Существует ли общий способ адаптации шаблона функции к объекту полиморфной функции?
У меня есть некоторые шаблоны функций, например
template <typename T>
void foo(T);
template <typename T>
void bar(T);
// others
и мне нужно передать каждый алгоритм, который будет называть его различными типами, например
template <typename F>
void some_algorithm(F f)
{
// call f with argument of type int
// call f with argument of type SomeClass
// etc.
}
Я не могу передать в свой шаблон функции uninstantiated, но я не могу создать экземпляр с любым конкретным типом, потому что some_algorithm
нужно будет вызвать его с аргументами нескольких разных типов.
Я мог бы адаптировать мои функциональные шаблоны к объектам полиморфной функции, например
struct foo_polymorphic
{
template <typename T>
void operator()(T t)
{
foo(t);
}
};
а затем передайте его как some_algorithm(foo_polymorphic())
. Но для этого требуется написать отдельный адаптер для каждого из моих шаблонов функций.
Существует ли общий способ адаптации шаблона функции к объекту полиморфной функции, то есть к некоторому механизму, который я могу повторно использовать для каждого из шаблонов функций, которые мне нужно адаптировать, без необходимости объявить что-то отдельно для каждого?
Ответы
Ответ 1
В короткой версии проблемы задано перегруженное имя f
, как кратко написать объект ff
, чтобы ff(a0, a1, a2, ...)
в конечном итоге вызывал f(a0, a1, a2, ...)
.
Полиморфный функтор, как вы указываете сами, является обычным решением. Но он должен быть определен вне строки (поскольку у него есть член шаблона), поэтому я буду исправлять это недостаточно кратким для целей моего ответа.
В настоящее время лямбда-выражения дают мономорфный функтор, поэтому они близки, но не совсем там.
// set of functions overloaded on int and double
void f(int);
void f(double);
auto ff = [](int i) { return f(i); };
Как отметил GMan в комментариях, полиморфные лямбда были бы (должны?) быть решением для краткой записи полиморфных функторов inline.
В то же время можно написать вспомогательный элемент make_overload
, который объединяет в себе несколько функторов, таких, что
auto ff = make_overload(
[](int arg0) { return f(arg0); }
, [](double arg0) { return f(arg0); } );
будет "захватывать" весь набор перегрузок. Возможно, макрос Boost.Preprocessor может помочь здесь, так что auto ff = POLYMORPHIC_LAMBDA( 1, (int)(double), { return f(arg0); } );
будет использоваться inline. Однако я подозреваю, что существуют ограничения на arity (следовательно, первый макро-аргумент), в отличие от обычного внекорневого рукописного полиморфного функторного решения; так что это не помогло бы, например, шаблоны вариационной функции.
Ответ 2
Почему вы не могли использовать параметры шаблона шаблона? Вы сказали, что не можете передать свой шаблон необоснованным, но я не уверен, что вы слышали об этом раньше, скажите мне, есть ли у вас, и это не сработает.
Я не знаю, как выглядит ваша структура кода, но вы можете сделать что-то вроде
Я знаю, что это работает, не знаю, насколько это уместно:
template<typename T>
T some_algorithm(T data) { return T(); } // just returning nothing for example
template<typename T, T(*Something)(T)>
class FuncClass {
public:
T run(T data) { return Something(data); }
};
template<typename T, typename Functor>
void apply_algorithm(T data) {
Functor F;
F.run(data);
}
int main() {
int mydata = 4;
apply_algorithm<int, FuncClass<int, some_algorithm<int> > >(mydata);
cin.get();
}