背景
之前的文章里我们分析过函数模板实例化的过程,可以参考这里,没搞明白的一定要搞清楚,不然后面越来越迷糊。现在类模板又是一种新的实例化流程,因为类模板有偏特化,所以和函数还不太一样。
流程
- 首先实例化非偏特化模板,如果报错就截止,这里注意,因为类在编译的时候不会执行,所以只要模板参数个数对齐就可以
- 上面没有报错的话,接着示例化各个偏特化模板,选着一个偏特化个数最多的模板作为最后的结果
demo
- 报错
#include <iostream>
template<class T, class Enable >
class A {
public:
A() { std::cout << "primary template\r\n"; }
}; // primary template
template<class T>
class A<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:
A() { std::cout << "partial specialization\r\n"; }
}; // specialization for floating point types
int main() {
A<double> a;
}
//error: too few template arguments for class template 'A'
这里会报错,所以为了使用偏特化的功能,我们最好给Enable 改名给 dummy, 而且给一个默认赋值void, 不用担心和后面偏特化有竞争,即使一样编译器也会优先选择偏特化版本, 不会报错。
#include <iostream>
template<class T, class dummy = void>
class A {
public:
A() { std::cout << "primary template\r\n"; }
}; // primary template
template<class T>
class A<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:
A() { std::cout << "partial specialization\r\n"; }
}; // specialization for floating point types
/* First instantiated from: insights.cpp:47 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class A<double, void>
{
public:
inline A()
{
std::operator<<(std::cout, "partial specialization\r\n");
}
};
int main() {
A<double> a;
}
可以看到,原模板也可以生成同样的实力,但是编译器优先选择符合的偏特化版本。
#include <iostream>
template<class T, class dummy = void >
class A {
public:
A() { std::cout << "primary template\r\n"; }
}; // primary template
template<class T>
class A<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:
A() { std::cout << "partial specialization\r\n"; }
}; // specialization for floating point types
template<class T>
class A<T, typename std::enable_if<std::is_same<T,double>::value>::type> {
public:
A() { std::cout << "second specialization\r\n"; }
}; // specialization for floating point types
int main() {
A<double> a;
}
//ambiguous partial specializations of 'A<double>'
如果有两个一模一样的偏特化版本,那么就会编译报错。