partial template specialization
部分模板专业化
允许为给定类别的模板参数自定义类模板。
句法
template < parameter-list > class-key class-head-name < argument-list > declaration | | |
---|
其中,类头名称标识先前声明的名称。类模板.本声明必须在同一份声明中命名空间或者,为了成员模板,类作用域作为其专长的主要模板定义。
例如,
二次
template<class T1, class T2, int I>
class A {}; // primary template
template<class T, int I>
class A<T, T*, I> {}; // #1: partial specialization where T2 is a pointer to T1
template<class T, class T2, int I>
class A<T*, T2, I> {}; // #2: partial specialization where T1 is a pointer
template<class T>
class A<int, T*, 5> {}; // #3: partial specialization where T1 is int, I is 5,
// and T2 is a pointer
template<class X, class T, int I>
class A<X, T*, I> {}; // #4: partial specialization where T2 is a pointer
二次
标准库中的部分专门化示例包括std::unique_ptr
,它对数组类型具有部分专门化。
参数列表
以下限制适用于部分模板专门化的参数列表:
1%29参数列表不能与非专用参数列表%28相同,它必须专门化%29。
二次
template<class T1, class T2, int I> class B {}; // primary template
template<class X, class Y, int N> class B<X,Y,N> {}; // error
二次
Moreover, the specialization has to be more specialized than the primary template. template | (since C++14) |
---|
2%29默认参数不能出现在参数列表中
3%29如果任何参数是包扩展,则必须是列表中的最后一个参数。
4%29非类型参数表达式不能使用模板参数的名称,除非它恰好是模板参数%28的名称,除非C++14%29 Non类型参数表达式可以使用模板参数,只要该参数至少出现在非推断语境%28自C++14%29
二次
template <int I, int J> struct A {};
template <int I> struct A<I+5, I*2> {}; // error, I is not deducible
template <int I, int J, int K> struct B {};
template <int I> struct B<I, I*2, 2> {}; // OK: first parameter is deducible
二次
5%29非类型模板参数不能专门化其类型取决于专门化参数的模板参数:
二次
template <class T, T t> struct C {}; // primary template
template <class T> struct C<T, 1>; // error: type of the argument 1 is T,
// which depends on the parameter T
template< int X, int (*array_ptr)[X] > class B {}; // primary template
int array[5];
template< int X > class B<X,&array> { }; // error: type of the argument &array
// is int(*)[X], which depends on the parameter X
二次
名称查找
不通过名称查找找到部分模板专门化。只有在通过名称查找找到主模板时,才会考虑其部分专门化。特别是,使主模板可见的使用声明也使部分专门化可见:
二次
namespace N {
template<class T1, class T2> class Z { }; // primary template
}
using N::Z; // refers to the primary template
namespace N {
template<class T> class Z<T, T*> { }; // partial specialization
}
Z<int,int*> z; // name lookup finds N::Z (the primary template),
// the partial specialization with T = int is then used
二次
偏序
当类模板被实例化,并且有部分专门化可用时,编译器必须决定主要模板是要使用还是它的部分专门化之一。
1%29如果只有一个专门化与模板参数匹配,则使用该专门化。
2%29如果多个专门化匹配,则使用偏序规则来确定哪个专门化更专业化。使用最专门的专门化,如果它是唯一的%28,如果它不是唯一的,则程序不能编译%29。
3%29如果没有匹配的专门化,则使用主模板。
二次
// given the template A as defined above
A<int, int, 1> a1; // no specializations match, uses primary template
A<int, int*, 1> a2; // uses partial specialization #1 (T=int, I=1)
A<int, char*, 5> a3; // uses partial specialization #3, (T=char)
A<int, char*, 1> a4; // uses partial specialization #4, (X=int, T=char, I=1)
A<int*, int*, 2> a5; // error: matches #2 (T=int, T2=int*, I=2)
// matches #4 (X=int*, T=int, I=2)
// neither one is more specialized than the other
二次
非正式地说,“A比B更专业”的意思是“A接受的类型比B少”。
从形式上讲,为了在部分专门化之间建立更多的专门化--而不是特定的关系,首先将每个部分转换为一个虚拟函数模板,如下所示:
- 第一个函数模板具有与第一个部分专门化相同的模板参数,并且只有一个函数参数,其类型是类模板专门化,其中包含第一个部分专门化的所有模板参数。
- 第二个函数模板具有与第二个部分专门化相同的模板参数,并且只有一个函数参数,其类型是类模板专门化,其中包含来自第二个部分专门化的所有模板参数。
然后,函数模板将被排列为函数模板重载...
二次
template<int I, int J, class T> struct X { }; // primary template
template<int I, int J> struct X<I, J, int> {
static const int s = 1;
}; // partial specialization #1
// fictitious function template for #1 is
// template<int I, int J> void f(X<I, J, int> #A
template<int I> struct X<I, I, int> {
static const int s = 2;
}; // partial specialization #2
// fictitious function template for #2 is
// template<int I> void f(X<I, I, int> #B
int main()
{
X<2, 2, int> x; // both #1 and #2 match
// partial ordering for function templates:
// #A from #B: void(X<I,J,int>) from void(X<U1, U1, int>): deduction ok
// #B from #A: void(X<I,I,int>) from void(X<U1, U2, int>): deduction fails
// #B is more specialized
// #2 is the specialization that is instantiated
std::cout << x.s << '\n'; // prints 2
}
二次
部分专门化成员
部分专门化成员的模板参数列表和模板参数列表必须与部分专门化的参数列表和参数列表匹配。
就像主模板的成员一样,只有在程序中使用时才需要定义它们。
部分专门化的成员与主模板的成员无关。
部分专门化成员的显式%28%29专门化声明方式与主模板的显式专门化相同。
二次
template<class T, int I> // primary template
struct A {
void f( // member declaration
};
template<class T, int I>
void A<T,I>::f() { } // primary template member definition
// partial specialization
template<class T>
struct A<T,2> {
void f(
void g(
void h(
};
// member of partial specialization
template<class T>
void A<T,2>::g() { }
// explicit (full) specialization
// of a member of partial specialization
template<>
void A<char,2>::h() {}
int main() {
A<char,0> a0;
A<char,2> a2;
a0.f( // OK, uses primary template’s member definition
a2.g( // OK, uses partial specialization's member definition
a2.h( // OK, uses fully-specialized definition of
// the member of a partial specialization
a2.f( // error: no definition of f() in the partial
// specialization A<T,2> (the primary template is not used)
}
二次
如果一个类模板是另一个类模板的成员,并且它有部分的专门化,那么这些专门化就是封闭类模板的成员。如果将封闭模板实例化,则每个成员部分专门化的声明也会实例化%28--与模板的所有其他成员的声明(但不是定义)的方式相同--实例化%29。
如果主成员模板显式地为封闭类模板的给定%28隐式%29专门化的%28%29专门化,则对于封装类模板的此专门化,成员模板的部分专门化将被忽略。
如果成员模板的部分专门化显式地专门化了给定的封闭类模板的%28隐式%29专门化,则仍然会考虑主成员模板及其其他部分专门化。
二次
template<class T> struct A { // enclosing class template
template<class T2>
struct B {}; // primary member template
template<class T2>
struct B<T2*> {}; // partial specialization of member template
};
template<>
template<class T2>
struct A<short>::B {}; // full specialization of primary member template
// (will ignore the partial)
A<char>::B<int*> abcip; // uses partial specialization T2=int
A<short>::B<int*> absip; // uses full specialization of the primary (ignores partial)
A<char>::B<int> abci; // uses primary
二次
缺陷报告
以下行为更改缺陷报告追溯应用于先前发布的C++标准。
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 1315 | C++14 | template parameter could not be used in non-type arg expressions other than id-expresisons | expressions ok as long as deducible |
© cppreference.com
在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。