本章会介绍一些模板的奇技淫巧。
5.1 用 typename 避免歧义
typename
可用于表示变量是一个类型。
template<typename T>
class MyClass {
public:
...
void foo() {
typename T::SubType* ptr;
}
};
这里,SubType
是在 T
类型里定义的。如果这里不用 typename
,SubType
会被认为是某个非类型的数据(例如某个静态变量,或是枚举类),于是 T::SubType* ptr
就被当作了一个乘法。
结论是,当某个类型依赖于模板参数时必须用 typename
说明。
例如,如下程序可以打印标准库容器的元素:
#include <iostream>
// print elements of an STL container
template<typename T>
void printcoll(T const& coll)
{
for (typename T::const_iterator iter=coll.begin(); iter != coll.end(); iter++)
{
std::cout << *iter << " ";
}
std::cout << std::endl;
}
注意到我们使用了 typename
来指明 T::const_iterator
是一个类型。
5.2 零值初始化
对于基础类型如 int
, double
,没有默认构造函数来用默认值初始化,因此,对于以下模板:
template<typename T>
void foo()
{
T x; // x has undefined value is T is built-in type
}
对于基本类型,这个模板会初始化成未定义的值。自c++11开始,我们可以改进为:
template<typename T>
void foo()
{
T x{}; // x has zero value is T is built-in type
}
5.3 使用 this
如果某个类继承自模板类,x
并不一定等于 this->x
。
#include <iostream>
template<typename T>
class Base {
public:
void bar() {std::cout << "Base::bar is called" << std::endl;}
};
template<typename T>
class Derived : Base<T> {
public:
void foo() {
this->bar(); // if "this" is not used here, bar() can't be found
}
};
结论:基类是模板类时,子类调用基类的方法需要使用 this->
或 Base<T>::
。
5.4 template for raw arrays and string literals
略,不常用
5.5 类成员模板
5.5.1 使用 template
避免歧义
当调用模板类成员时,有时需要指明模板参数。这时候需要使用 template
关键字来确保第一个 <
不被当做“小于”处理。例如:
template<unsigned long N>
void printBitset(std::bitset<N> const& bs) {
std::cout << bs.template to_string<char, std::char_traits<char>, std::allocator<char>>();
}
这里是调用了 std::bitset
中的模板类成员函数:
template<class CharT = char,
class Traits = char_Traits<CharT>,
class Allocator = allocator<CharT>>
basic_string<CharT, Traits, Allocator>
to_string(CharT zero = CharT('0'), CharT one = CharT('1')) const;
如果这里不使用 template
,编译器会认为 <
是“小于”符号。这个问题仅在它前面的变量依赖于模板参数时存在。例如,这里 ts
变量就是依赖于模板参数 N
。
结论:template
关键字仅在模板中使用,且仅在调用依赖模板参数的方法时使用。
5.5.2 Generic Lambdas
c++14 引入了 generic lambdas,可以作为成员模板的简化。例如以下例子可以计算任意类型的和:
// c++14 or above
auto lambda_sum = [](auto x, auto y) {return x + y;};
它是以下例子的简化:
class MySum {
public:
template<typename T1, typename T2>
auto operator() (T1 x, T2 y) const {
return x + y;
}
};
网友评论