Шаблоны функций и шаблоны классов дополняют друг друга (я называю их ортогональными, но вы можете не соглашаться), и в шаблонном метапрограммировании они фактически служат ортогональным целям.
Шаблоны классов позволяют вам шаблонсовпадение в аргументе шаблона, т.е.они обеспечивают частичную специализацию .
Шаблоны функций, напротив, не допускают частичную специализацию, но они позволяют вычитать аргументы шаблона , что означает, что вы этого не делаетеЯ должен написать аргументы шаблона явно (за исключением дополнительных аргументов, как в вашем примере).
Это, я думаю, объясняет различия в синтаксисе, поскольку они различаются в том, чего они могут достичь.Более того, шаблоны функций могут иметь перегрузки, шаблоны классов не могут.
Способ объединить обе концепции -
1) иметь шаблоны классов помощников со статическими функциями, не являющимися шаблонами, если вы хотите частичную специализацию для функциишаблоны:
template <typename T>
struct doSomethingWithPointersHelper
{
static void act(T x) { ... }
};
template <typename T>
struct doSomethingWithPointersHelper<T*>
{
static void act(T* x) { ... }
};
// This acts as if we had a partial specialization
// for pointer types
template <typename T>
doSomethingWithPointers(T x)
{ return doSomethingWithPointersHelper<T>::act(x); }
Существуют и другие способы достижения этого в отдельных случаях, но этот подход всегда работает.
2) Наличие вспомогательных шаблонных функций, если вы хотите использовать аргументную дедукциюпри построении сложных классов:
template <typename T, typename U>
struct MyComplexClass
{ ... };
template <typename T, typename U>
MyComplexClass<T, U> makeComplex(T t, U u)
{ return MyComplexClass<T, U>(t, u); }
в стандартной библиотеке вы найдете make_pair
, bind1st
или mem_fun
, которые используют эту технику.