Effective Modern / Effective / More Effective C++ Notes
Effective Modern C++
Chap-1类型推导
Item 1 理解模板类型推导
要点
- 在模板推导过程中,具有引用类型的实参会被当成非引用类型来处理。换而言之,起引用性会被忽略,指针类型亦是如此
- 对万能引用形参进行推导时,左值实参会进行特殊处理,也就是形参对引用性会被保留
- 对按值传递的形参进行推导时,若实参类型中带有
const
或volatile
饰词,则对它们还是会被当作不带const
或volatile
饰词的类型来处理,引用性也会被忽略- 在模板类型推导过程中,数组或函数类型的实参会退化成对应的指针,除非它们被用开初始化引用
1 | template<typename T> |
情况1,ParamType是个引用或指针,但不是个万能引用
1 | template<typename T> |
上述代码中T未被推导为引用或者指针,因为其引用性/指针性在推导过程中被忽略 – 要点1
情况2,ParamType是个万能引用
1 | template<typename T> |
上述代码中T得引用性被保留 – 要点2
情况3,ParamType既非指针也非引用
传值
1 | template<typename T> |
上述代码中传值方式的param是一个副本,忽略其const和引用性 – 要点3
数组实参
1 | const char name[] = "J. P. Brigss"; // name的类型是const char[13] |
数组引用的模板类型可以被推导成数组类型,包含数组size,利用该特性可以在编译时推导出数字个数 – 要点4
以下函数被声明为constexpr,以编译时常量形式返回数组size
1 | template<typename T, std::size_t N> |
函数实参
1 | void someFunc(int, double); |
Item 2 理解auto类型推导
要点
- 一般情况下,auto类型推导和模板类型推导是一模一样的,但是auto类型推导会假定用大括号括起的初始化表达式代表一个
std::initializer_list
,但是模板类型推导却不会- 在函数返回值或lambda式的形参中使用auto,意思是使用模板类型推导而非auto类型推导
auto类型推导类似模板参数推导,可以参照Item 1中的推导规则,也分3类情况
- 情况 1: 类型饰词是指针或引用,但不是万能引用
- 情况 2: 类型饰词是万能引用
- 情况 3: 类型饰词既非指针也非引用
1 | auto x = 27; // 情况3,x类型是int |
模板推导无法推导出{}的类型,auto类型推导可以,但是auto是返回值或lambda形参时使用模板推导
1 | template<typename T> |
Chap-3 转向现代C++
Item 7 在创建对象时注意区分()和{}
要点
- 大括号初始化可以应用的语境最为宽泛,可以阻止隐式窄化型转换,还对C++最令人苦恼的解析语法(most vexing parse)免疫
- 在构造函数重载决议期间,只要有任何可能,大括号初始化就会与带有std::initializer_list型别的形参相匹配,即使其他重载版本有着貌似更加匹配的形参表
- 使用小括号还是大括号,会造成结果大相径庭的一个例子是:使用两个实参来创建一个std::vector< 数值类型 >对象。
- 在模板内容进行对象创建时,到底应该使用小括号还是大括号会成为一个棘手问题。
C++11引入了统一初始化,概念上是可以用于一切场合,表达一切意思的初始化。它的基础是大括号形式,“统一初始化”是为其里,“大括号初始化”是为其表。
1 | int x(0); // 初始化物在小括号内 |
使用大括号会进行窄化检查,避免苦恼解析,参考要点1
1 | double x, y, x; |
大括号初始化的缺点是会伴随意外行为,要点2,3
1 | class Widget { |
Item 8 优先选用nullptr,而非0或NULL
要点
- 相对于0或NULL,优先选用nullptr。
- 避免在整型和指针类型之间重载。