Есть ли способ передать шаблонную подпись функции в качестве параметра шаблона шаблона
С помощью шаблонных параметров шаблона можно передать классу шаблонный класс без указания типов по его параметрам. Мне было интересно, есть ли способ перейти к шаблону шаблона шаблона шаблонной сигнатуры функции, чтобы иметь возможность специализировать, какой вариант функции следует считать вперед.
Чтобы быть ясным - я знаю, что не могу этого сделать:
template <class T>
void foo() { /*...*/ }
template <template <class...> class FooType>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo)> f;
}
Но каким-то образом я хотел бы получить шаблонную подпись функции до Foo
. Возможно ли это?
Ответы
Ответ 1
В приведенном ниже примере у одного есть шаблонный шаблонный параметр, который принимает предпочтительную подпись для функции.
Из-за специализации и отсутствия тела для класса шаблона принимаются только типы для вызовов.
Это обобщение того, что фактически спросил ОП:
#include<cassert>
template<typename F>
struct S;
template<typename R, typename... Args>
struct S<R(Args...)> {
using type = R(*)(Args...);
};
template<template<typename> class F>
struct T {
typename F<void(int)>::type ft;
typename F<double(double, double)>::type gt;
};
void f(int) { }
double g(double x, double y) { return x+y; }
int main() {
T<S> t;
t.ft = f;
t.gt = g;
t.ft(42);
auto v = t.gt(1., 1.);
assert(v == 2.);
}
Ответ 2
Я не мог поверить, что это невозможно, поэтому я немного искал и нашел способ сделать именно то, что хотел. Я использовал templated using
с синтаксисом:
template <template<class... Args> class FooType>
struct Foo {
FooType<int> ft;
};
template <class Res, class... Args>
using FooSignature = Res(*)(Args...);
int foo() {
return 1;
}
int main() {
Foo<FooSignature> f;
f.ft = foo;
}
Однако это все еще оставляет вопрос, как это возможно, поскольку стандарт утверждает что-то противоположное.
Ответ 3
Шаблон шаблона по-прежнему является шаблоном.
template <class T>
void foo() { /*...*/ }
template <typename T>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo<int>)> f;
}
Ответ 4
Как можно видеть в этом ответе
Шаблон указателя функции является незаконным в С++
Стандарт С++ говорит в $14/1,
Шаблон определяет семейство классов или функций.
Дальнейшее цитирование из связанного ответа:
Обратите внимание, что он НЕ говорит: "Шаблон определяет семейство классов, функций или указателей функций"
Однако вы можете передавать конкретные указатели функций и специализироваться на их сигнатуре:
#include <iostream>
template <class T>
void foo(T) { }
template <typename>
struct Foo;
template<typename T>
struct Foo<void(T)>
{
void cb() { std::cout << "T\n"; }
};
template<>
struct Foo<void(int)>
{
void cb() { std::cout << "int\n"; }
};
template<>
struct Foo<void(double)>
{
void cb() { std::cout << "double\n"; }
};
int main()
{
Foo<decltype(foo<int >)>().cb(); // outputs 'int'
Foo<decltype(foo<double>)>().cb(); // outputs 'double'
Foo<decltype(foo<char >)>().cb(); // outputs 'T'
return 0;
}
Ответ 5
Вы не можете передать шаблон функции в качестве аргумента. Что вы можете сделать, это обернуть шаблон функции в генерации лямбда с параметром тега:
template <class T> struct tag_t { using type = T; };
template <class T>
void foo() { ... }
template <class F>
void call_func_with(F f) {
f(tag_t<int>{} );
f(tag_t<double>{} );
}
call_with_func([](auto tag) { foo<decltype(tag)::type>(); } );
Здесь f(tag_t<X>{} )
завершает вызов foo<X>()
по желанию.