变参模板
变参模板(Variadic Templates),能够接受任意参数的模板1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// example 1
void print() {}
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args)
{
cout << firstArg << " " << sizeof...(args) << endl; // 每次能处理的只有 firstArg
print(args...); // args...只能往下传递
}
// ----------------------------------------------------
// ...就是一个所谓的 pack(包)
// 用于 template parameters,就是 template parameters pack (模板参数包)
// 用于 function parameter types,就是 function parameter types pack (函数参数类型包)
// 用于 function parameters,就是 function parameters pack (函数参数包)
// 加上...表示可以接受任意个参数,要注意其位置;
// 一定要写一个处理最后情况的函数,这其实就像是递归,必须处理最简单的情况
实际使用1:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class CustomerHash {
public:
std::size_t operator()(const Customer& c) const {
return hash_val(c.fname, c.lname, c.no);
}
};
// 1. 最泛化的,设置 seed 后开始递归,不设置 seed 根本进不去 2.
template <typename... Types>
inline size_t hash_val(const Types&... args) {
size_t seed = 0;
hash_val(seed, args...);
return seed;
}
// 2. 递归函数
template <typename T, typename... Types>
inline void hash_val(size_t& seed, const T& val, const Types&... args) {
hash_combine(seed, val);
hash_val(seed, args...);
}
// 3. 递归函数的结尾
template <typename T>
inline void hash_val(size_t& seed, const T& val) {
hash_combine(seed, val);
}
// 4. 实际计算 hash 的函数
template <typename T>
inline void hash_val(size_t& seed, const T& val) {
seed ^= std::hash<T>(val) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
实际使用2:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16template <typename... Values> class tuple; // 泛化
template <> class tuple<> {}; // 特化
template <typename Head, typename... Tail>
class tuple<Head, Tail...> : private tuple<Tail...>
{
typedef tuple<Tail...> inherited;
public:
tuple() {};
tuple(Head v, Tail... vtail):m_head(v), inherited(vtail...) {};
typename Head::type head() { return m_head; }
inherited& tail() { return *this; }
protected:
Head m_head;
};
模板表达式里的空间
nullptr 和 std::nullptr_t
一个新的关键字,空指针1
2
3
4
5void f(int);
void f(void *);
f(0); // calls f(int)
f(NULL); // calls f(int)
f(nullptr); // calls f(void *)
自动类型推断 auto
尽量只在类型过于复杂、书写太长,或者类型难以推断的地方1
2
3
4
5
6
7
8
9auto i = 42; // i has type int
double f();
auto d = f(); // d has type double
vector<string> v;
auto pos = v.begin(); // pos has type vector<string>::iterator,类型太长,懒得写
auto l = [](int x)->bool{ // l has type of a lambda,类型过于复杂
...,
};
Uniform Initialization
初始化可能在小括号、大括号和赋值操作符之间发生1
2
3
4
5
6
7int value[] {1,2,3}; // initializer_list<T>
vector<int> v {2,3,5,7,11,13,17}; // 容器中有可以接受initializer_list<T>的ctor
complex<double> c{4.0, 3.0};
Rect r1 = { 3,7,20,25,&area, &print };
Rect r1(3,7,20,25);
int ia[6] = { 27,210,12,47,109,83 };
Initializer Lists
Initializer Lists的一些示例
1 | int i; // i 的值不确定 |
模板类std::initializer_list<>
1 | // 示例1 |
explicit
explicit for ctors,表示这个ctor必须被明确调用才行,不允许编译器做隐式转换。
示例如下:
1 | struct Complex |
range-based for statement
1 | for ( decl : coll ) { |
1 | for (int i : { 2, 3, 5, 7, 9, 13, 17, 19}) { |
1 | vector<double> vec; |
=default, =delete
如果自行定义了一个ctor,那么编译器就不会再给你一个default ctor;
如果你强制加上 =default,就可以重新获得并使用 default ctor;
1 | class Zoo |
Alias Template (template typedef)
Alias:化名,别名
1 | template <typename T> |
等价于:
1 | std::vector<int, MyAlloc<int>> coll; |
typedef 没法指定类型参数
1 | typedef std::vector<int, MyAlloc<int>> Vec; |
Type Alias
和 typedef 相似
1 | // typedef void (*func)(int, int); 等价于下式 |
using关键字
1 | using namespace std; // 命名空间 |
noexcept关键字
1 | void foo() noexcept; <=> void foo() noexcept(true); |
保证函数不会丢出异常;noexcept(...)
中可以指定boolean表达式,表面在某种情况下不丢出异常;
override关键字
作用于虚函数
1 | struct Base{ |
1 | struct Derived2: Base { |
final关键字
用于类,则该类不能被继承;用于函数,则该函数不能被重写;
1 | struct Base1 final {}; |
1 | struct Base2 { |
decltype
使用decltype,可以让编译器找到一个expression的类型
1 | map<string, float> coll; |
用法:
声明返回类型
1
2
3
4
5template <typename T1, typename T2>
decltype(x+y) add(T1 x, T2 y); // 编译出错:编译器先看到x,y,但是前面没出现过
=>
template <typename T1, typename T2>
auto add(T1 x, T2 y) -> decltype(x+y);
适用于metaprogramming
1
2
3
4
5template <typename T>
void test_decltype(T obj){} // T必须是容器
typedef typename T::iterator iType;
=> typedef typename decltype(obj)::iterator iType;传递 lambda 的类型
1
2
3auto cmp = [](const Person& p1, const Person& p2) { ... };
// 必须传递cmp给coll;否则coll会调用cmp的默认ctor,但cmp是lambda,没有默认构造函数,就会报错。所以必须这么传递
std::set<Person, decltype(cmp)> coll(cmp);
Lambda
lambda就是可以在语句或表达式中定义的函数,这个函数可以被作为参数或者局部变量;
lambda是一个对象,功能上是一个函数;
1 | [...](...) mutable throwSpec -> retType { ... } |
1 | // 示例 |