讲一下模版特化和偏特化的区别
问题
讲一下模版特化和偏特化的区别
我的回答
模板特化其实就是说,我们写了一个通用的模板,但是对于某些特定的类型,我们想要一个不一样的实现。
比如说,我写了一个通用的容器类,对于大部分类型都工作得很好,但是对于bool类型,我想要做一些特殊的优化,那我就可以专门为bool写一个版本,这就是特化。
特化分两种:
一种叫全特化,就是我把所有的模板参数都给确定了。比如我的模板有T这个参数,我说T就是int,没别的了,这就是全特化。
另一种叫偏特化,就是我只确定一部分。比如我的模板有两个参数T和U,我说U必须是int,但T你随便,或者我说T和U必须是同一个类型,但具体是什么类型你随便。这就是偏特化。
区别主要就是,全特化把所有参数都定死了,偏特化只定了一部分。还有就是函数模板只能全特化,不能偏特化,但类模板两种都可以。关于函数模板为什么不支持偏特化:
主要原因是函数有重载机制。C++设计者认为,如果你想要对函数模板的某些参数进行特殊处理,直接写一个重载函数就行了,没必要搞偏特化这么复杂。
比如说:
template<typename T>
void func(T value) { cout << "通用版本"; }// 想要对指针类型特殊处理?直接重载就行
template<typename T>
void func(T* value) { cout << "指针版本"; }
而且函数重载的匹配规则已经很复杂了,如果再加上偏特化,编译器选择函数的规则就会变得更加复杂,容易出错。所以C++标准就规定函数模板只能全特化,想要类似偏特化的效果就用重载。
编译器会自动选择最合适的版本,越具体的版本优先级越高。
// 通用模板
template<typename T>
class Container {
public:void print() { cout << "通用版本"; }
};// 全特化 - 专门为char*写的
template<>
class Container<char*> {
public:void print() { cout << "这是字符串版本"; }
};// 偏特化 - 专门为指针类型写的
template<typename T>
class Container<T*> {
public:void print() { cout << "这是指针版本"; }
};
这样的话,如果我写Container<int>,会用通用版本;写Container<char*>会用全特化版本;写Container<int*>会用偏特化版本。编译器会自动帮我们选择最合适的。