类模版与成员函数模版
我们可以使用template
来引入类模版;
template <typename T>
class B{
};
关于类模版,我们需要注意以下几点
- 类模版的声明与定义需要满足翻译单元级别的一处定义原则
- 成员函数只有在调用时才会被实例化
- 类模版名称在模版类内或者模版成员函数内可以进行简写
template <typename T> class B{ public: auto fun(){ return B{}; // 编译器自动视为B<T> } };
- 类模版成员函数的定义(类内、类外)
template <typename T> class B{ public: void fun(); }; template <typename T> void B<T>::fun(){ }
接下来后我们来讨论成员函数模版,主要分为以下两类:
- 类的成员函数模版
class B{ public: template<typename T> void fun(){ } };
- 类模版的成员函数
template <typename T> class B{ public: template<typename T2> void fun(){ } };
之后我们来讨论友元函数模版,我们可以声明函数(模版)为某个类(模版)的友元
template <typename T>
class B{
public:
template<typename T2>
friend void fun(){
}
};
template <typename T>
class B{
friend void fun(B input){
std::cout << input.x << std::endl;
}
private:
int x;
};
在C++11之后还支持声明模版参数为友元
template <typename T>
class B{
friend T;
private:
int x;
};
最后,和函数模版一样,我们需要关注类模版的实例化、特化与实参推导
-
类模版的实例化:类模版的实例化与函数模版的实例化很像,可以实例化整个类,也可以实例化类中的某个函数,具体参考这里
-
类模版的(完全)特化/部分特化(偏特化):特化版本与基础版本可以拥有完全不同的实现
// 完全特化 template <typename T> struct B{ void fun(){ std::cout << "1\n"; } }; template<> struct B<int>{ void fun(){ std::cout << "2\n"; } };
// 偏特化 template <typename T, typename T2> struct B{ void fun(){ std::cout << "1\n"; } }; template <typename T2> struct B<int,T2>{ void fun(){ std::cout << "2\n"; } };
-
类模版的实参推导(C++17开始)
- 基于构造函数的实参推导
template <typename T> struct B{ B(T input){ } }; int main() { B x(3); }
- 用户自定义的推导指引,具体参考这里
注意,引入了实参推导并不意味着降低了类型限制
在C++17之前,我们可以引入辅助函数模版来实现类模版的实参推导
template <typename T1, typename T2> std::pair<T1,T2> make_pair(T1 val1, T2 val2){ return std::pair<T1,T2>(val1,val2); } int main() { auto x = make_pair(3,3.14); }
- 基于构造函数的实参推导