模板偏特化对参数列表的要求
模板偏特化对参数列表的要求
cpp官方文档会搞混parameter list和argument list的区别,因此不要只看文字描述
模板偏特化的声明方式

1.argument list不能和主模板的argument list相同
对于下面这份声明,argument list即syntax中的部分


正确的偏特化
template<class T1, class T2, int I> class B {}; // primary template
template<class X, int N> class B<X, int, N> {}; // 偏特化,第二个参数固定为 int
2.偏特化时,默认参数不能在参数列表中使用
template<class T1, int I, class T2 = int> class B {}; // primary template
template<class X, int Y = 1> class B<X,Y> {}; // error

3. 参数包必须放在参数列表的最后一个
4. 常数参数表达式可以出现在参数列表中,只要表达式中的参数有一次出现在能够被推导的场景
template<int I, int J> struct A {};
template<int I> struct A<I + 5, I * 2> {}; // error, I is not deducible
假如实例化A<10,10>时,认为I=5满足,所以I可以推导。但编译器不会进行这种解方程式的推导
凡是出现这种“先对模板参数做 加法、乘法、取成员、调用 typedef、调用类型萃取……再去匹配”的上下文,都被视为“非可推导上下文”
下面这段,第一个模板实参直接写成了I,这个I符合“直接把模板参数当作占位符去匹配实参”的场景。
那么在实例化B<10,12,10>时,编译器就能先直接推导I=10,然后再去检查后面两个模板参数是否匹配,不匹配则不带入相应的模板
template<int I, int J, int K> struct B {};
template<int I> struct B<I, I * 2, 2> {}; // OK: first parameter is deducible
根据 C++ 标准(参见 [temp.deduct.type] 节),“非可推导上下文”包括但不限于:
作为非类型模板参数的子表达式,例如 I+5、I2、I-3、4I、I<<1、I|7 等任意算术或逻辑运算,都被视为“转换之后的表达式”,不用于直接推导。
做了类型变换或包装 的情况,比如 std::remove_reference_t
、typename X ::type、或者任意通过 decltype(...)、pointer_traits<...>::element_type 等做的中间运算,这些都会导致“即便实参跟它最终结果匹配,也不会被当做可推导上下文”。
在花括号初始化、类型推导上下文里 等一些更特殊场景都有对应的条文。
5. “如果一个非类型模板参数(比如这里的 t)的类型依赖于另一个模板参数(也就是 T),那么你不可以在特化(特殊化、偏特化)的地方直接写一个固定的字面量来代表它。”
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
常数模板参数1特化了T t这个模板参数,但这个模板参数的类型依赖于其他的模板参数,违背了c++标准对“非类型模板参数必须与其声明类型严格匹配”的规定。
本文来自博客园,作者:ijpq,转载请注明原文链接:https://www.cnblogs.com/ijpq/p/18905366

浙公网安备 33010602011771号