Как заставить шаблонный аргумент работать с функциями?
Рассмотрим набор функций, таких как
template< class Fun >
void A( const Fun& )
{
}
template< class Fun >
void B( const Fun& )
{
}
template< class Fun >
void C( const Fun& )
{
}
предназначен для принятия типов функций в качестве аргументов. Тогда это совершенно нормально:
template< class T >
void Func( const T& )
{
}
A( Func< int > );
B( Func< int > );
C( Func< int > );
Теперь я хотел избавиться от повторения int
аргумент temaplate, поэтому я попробовал это:
template< class T >
struct Helper
{
template< template< class > class Fun >
static void A( Fun< T >& f )
{
A( f );
}
template< template< class > class Fun >
static void B( Fun< T >& f )
{
B( f );
}
...
};
typedef Helper< int > IntHelper;
IntHelper::A( Func ); //error
IntHelper::B( Func ); //
IntHelper::C( Func ); //
однако это не удается скомпилировать на GCC 4.5.1 ('error: no matching function for call to 'Helper<int>::A(<unresolved overloaded function type>)'
) и MSVC10 (cannot use function template 'void Func(const T &)' as a function argument
а также could not deduce template argument for 'overloaded function type' from 'overloaded function type'
).
Может кто-нибудь объяснить, почему именно, и есть ли способ обойти это?
редактировать хорошо, я понимаю, почему это невозможно сейчас; для ответов, содержащих обходной путь: в реальном коде есть много разных Func
S, скажем, 100, в то время как есть только около 6 функций, таких как A, B и C...
4 ответа
Форма template<class> class Fun
будь то объявление или параметр шаблона (как у вас), предназначен только для шаблонов классов, которые Func
нет. Это шаблон функции. Те имеют форму template</*parameters*/> Ret foo(/*parameters*/)
и они не допускаются в качестве параметров шаблона шаблона.
Вообще говоря, шаблонами функций нельзя манипулировать так же, как шаблонами классов.
Существует одна ситуация, когда вы можете избежать необходимости передавать параметры шаблона:
// Deduces that Func<int> is meant
void (*p)(int) = Func;
Тогда вы можете пройти p
в A
, B
а также C
,
(Аналогично, если у вас есть функция void f(void(*p)(int));
тогда вызов формы f(Func)
Это хорошо.)
Func
это шаблон функции, поэтому вы не можете передать его в качестве значения функции.
Вы также не можете передать его как параметр шаблона шаблона, потому что параметры шаблона шаблона должны быть шаблонами классов (не шаблонами функций).
Вы можете передать параметр шаблона шаблона, который оборачивает шаблон функции (например, возвращая его экземпляр из статической функции-члена):
template<class T> struct FuncHelper {
static void (*f())(const T &) { return &(Func<T>); }
};
template<typename T>
struct Helper
{
template< template< class > class Fun >
static void A()
{
A( Fun<T>::f() );
}
};
Helper<int>::A<FuncHelper>();
Хотя возможно использовать шаблон класса в качестве параметра шаблона, например,
template <typename> class Foo;
template <template <typename> class C> void doit() { /* ...*/ };
doit<Foo>();
(семантически) невозможно использовать шаблон функции в качестве параметра шаблона (отсутствует "указатель шаблона функции"). Обычным способом является использование функционального объекта, например
template <typename T>
struct Func
{
void operator()(T const &) const
{
/* ... */
}
};
template <typename T>
struct helper
{
template <template <typename> class F>
static void A()
{
A(F<T>);
}
// etc
};
typedef helper<int> int_helper;
int_helper::A<Func>();
Если Func
может быть объявлен как лямбда с auto
параметр типа (используя общие лямбды C++14), а затем определения A
, B
, а также C
не нужно менять, и может быть вызван без указания типа параметра:
auto Func = [](auto const&)
{
};
A(Func);
B(Func);
C(Func);