非类型模板参数
template<size_t N, typename T>
size_t ArraySize(T (&arr)[N])
{
return N;
}
inline和constexpr函数模板
template <typename T> inline T min(const T&, const T&);
在一个模板的作用域内,可以直接使用模板名而不必指定模板实参
模板别名
typedef Blob<string> strBlob;
template<typename T> using twin = pair<T,T>;
twin<string> authors;
C++假定通过作用域运算符访问的是名字不是类型
T::size_type * p // 编译器默认解释为两数相乘
template <typename T>
typename T::value_type top() {return typename T::value_type();} // 使用typename关键词指明当前是类型名
默认模板参数
template <typename T, typename F = less<T>>
int compare(const T &v1, const T &v2, F f = F())
{
...
}
成员模板不能是虚函数,但是模板类里可以使用模板参数进行虚函数定义
template<typename T>
class B
{
virtual T fun1() = 0; // 合法
template<typename M>
virtual M fun2() = 0; // 非法
};
类模板的成员模板
template<typename T>
class B
{
virtual T fun1() = 0; // 合法
template<typename M>
M fun2(); // 非法
};
template<T>
template<M>
M B<T>::fun2()
显示模板实参
template <typename T1, typename T2, typename T3>
T1 sum(T2, T3);
auto ret = sum<long long>(a,b);
尾置返回,使用decltype获取类型降低用户负担,且在使用模板时,由于编译器在遇到参数的参数列表之前,beg的定义不存在,所以必需使用尾置返回
template <typename It>
auto fcn(It beg, It end) -> decltype(*beg)
{
return *beg;
}
类型转换 P606
template <typename It>
auto fun2(It beg, It end) -> typename remove_reference<decltype(*beg)>::type
{
}
左值引用模板仅能接收左值,右值引用模板可以接收左值和右值,基于引用折叠实现,仅对非成员函数有效,成员函数跟随类模板的实例化,不会由编译器再次推断
template<typename T>
void fun(T&)
{
}
template<typename T>
void fun(T&&)
{
}
为了保证外层参数特性(引用|const),通过将一个函数参数定义为一个指向模板类型参数的右值引用,可以保持其对应实参的所有类型信息
template <typename F, typename T1, typename T2>
void filp(F f, T1 &&t1, T2 &&t2)
{
f(t2, f1);
}
使用std::forward保持类型信息
template <typename T> inter(T &&arg)
{
finalFcn(std::forward<T>(arg));
}
可变参数模板
template <typename T, typename... Args>
void foo(const T &t, const Args& ... rest);
sizeof…运算符用于获取包中多少元素
template <typename T, typename... Args>
void foo(const T &tm const Args& ... rest)
{
sizeof...(rest);
}
模板函数无法进行偏特化,但是可以进行特例化
template<class U> Widget* Create<Widget, U>(const U& arg); // 不允许进行偏特化
template<> Widget* Create(const SomeType& arg);
参考:C++ Primer 5th