这里是《C++ Templates 2th》的读书笔记
typename
关键字用于告诉编译器接下来的东西是类型而不是其他,比如:
1
2
3
4
5
|
template <typename T>
void foo() {
typename Class::InnerType a;
/* ... */
}
|
这里明确说明InnerType
是Class
内的类型,而不是静态成员变量或其他。
使用a{}
的方式对变量进行零初始化:
1
2
3
4
|
template <typename T>
void foo() {
T a{};
}
|
基本数据类型会被初始化,bool初始化为false,数值类型初始化为0。C++11之前用a()
的方式。
继承了模板类的子类,在调用父类的成员函数时需要显式地使用this
或者Base<T>::
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
template <typename T>
class Base {
public:
void DoSomething();
};
template <typename T>
class Derived: public Base<T> {
public:
void DoMyself() {
this->DoSomething();
// or use Base<T>::DoSomething();
}
};
|
全特化的函数被视为全局函数而非模板函数。这意味着在头文件中全特化某个模板函数时需要将这个函数声明为inline
:
1
2
3
4
5
6
7
8
9
|
template <typename T>
void foo() {
std::cout << "template foo" << std::endl;
}
template <>
inline void foo<int>() {
std::cout << "int foo" << std::endl;
}
|
某些时候需要使用template
关键字显式指定要调用的是模板成员函数:
1
|
std::cout << instance.template foo<int>(3) << std::endl;
|
这里如果不加template
,编译器会将<
视为小于的逻辑运算。
使用auto
关键字来使用泛型Lambda:
1
|
[](auto a, auto b) { return a + b; }
|
模板参数模板(Template Template Parameter)
指模板参数是一个模板,比如:
1
2
3
4
5
|
template <typename T, typename Cont>
class A {
public:
Cont container;
};
|
这里我们要存储的元素类型是T
,容器的类型时Cont
,但是我们使用的时候得指定容器内元素的类型:
1
|
A<int, std::vector<int>> a;
|
我们想这样写:
让C++自动推断容器元素类型。这个时候容器就必须变为模板参数模板:
1
2
3
4
5
6
7
|
template <typename T,
template <typename Elem, typename Allocator = std::allocator<T>>
class Cont>
class A {
public:
Cont<T> container;
};
|
这里要注意的是多出来的Allocator
模板参数,因为std::vector
的模板声明为:
1
2
3
4
|
template<
class T,
class Allocator = std::allocator<T>
> class vector;
|
它是有两个模板参数的,所以如果我们要用std::vector
作为其容器的话就必须将两个参数都适配上,这就是为什么Allocator
也要写的原因。
上面的代码中Elem
和Allocator
都没有用到,没用到的模板参数可以省略名字:
1
2
3
4
|
template <typename T,
template <typename, typename = std::allocator<T>>
class Cont>
class A;
|