Давайте посмотрим на синтаксис для специализации шаблона.Во-первых, вот шаблон
template<typename T> void bar() { std::cout << "generic\n"; }
Теперь, чтобы объявить специализацию, вы должны предоставить другое определение для этого шаблона с параметрами, «заполненными» для шаблона, являющимся специализированным:
void bar<int>() { std::cout << "special for int\n"; }
за исключением того, что вышеупомянутое не является законным, потому что специализация шаблона также должна быть шаблоном, с собственными параметрами, которые не совпадают с параметрами специализированного шаблона.В этом случае у нас нет других параметров, поэтому мы должны просто использовать пустой список параметров шаблона:
template<>
void bar<int>() { std::cout << "special for int\n"; }
Обратите внимание, что при «заполнении» параметров шаблона конкретные типы помещаются в одно и то же место.как они делают, когда вы используете шаблон, а не внутри template<...>
Вот код из этого другого вопроса о том, как специализировать один член шаблона класса для конкретной реализации объекта.template.
template <typename T>
struct Node
{
void split() { puts( "Default method" ) ; }
};
template<>
void Node<int>::split() { puts( "Int method" ) ; }
Это то же самое, что и
template <typename T>
struct Node
{
void split();
};
// A
template<typename T>
void Node<T>::split() { puts( "Default method" ) ; }
// B
template<>
void Node<int>::split() { puts( "Int method" ) ; }
Как видите, B
- это специализация A
, потому что Node<int>
in B
заполняетв параметрах A
.
Теперь посмотрите на ваш код:
template <typename T>
struct Node
{
void split() { puts( "Default method" ) ; }
template <int> void split() { puts( "Int method" ) ; }
};
Здесь никакой специализации нет.Ничто не «заполняет» параметры шаблона для какого-либо другого шаблона.
Так что же означает template<int>
?На первый взгляд вы можете подумать, что это означает, что вы «заполняете» некоторые template<typename T>
с помощью T
= int
, но это не так.Когда вы заполняете параметры шаблона для специализации, вы не делаете это внутри template<...>
.
Вместо этого template<int>
использует что-то, что называется «нетипичные параметры шаблона».В template<typename T>
вы создаете шаблон, который может быть создан для разных типов.Например:
template <typename T> void bar();
bar<Foo>();
bar<std::string>();
template<int>
- это одно и то же, за исключением того, что позволяет получать разные экземпляры для разных значений int
, а не для разных типов.См .:
template <int N> void baz();
baz<1>();
baz<INT_MAX>();
В одном случае параметром шаблона является typename
, и поэтому шаблон создается с типами.В другом случае параметр шаблона равен int
, и поэтому шаблон создается с значениями int
.
Вот пример шаблона, который использует нетипичные параметры шаблона:
template<int N>
struct array{
double arr[N];
};
array<3> k = {{ 0.0, 0.0, 1.0 }}; // has a member 'double arr[3]'
array<2> j = {{ 0.0, 1.0 }}; // has a member 'double arr[2]'
А вот еще один, где выводится значение N
:
template<typename T,int N>
int size_of_array(T (&my_array)[N]) { // N is deduced from the argument you pass size_of_array
return N;
}
double X[100];
std::cout << size_of_array(X) << '\n'; // instantiates size_of_array<double,100>