[Effective Modern C++] Item 7. Distinguish between () and {} when creating objects - 辨别使用()与{}创建对象的差别

条款7 辨别使用()与{}创建对象的差别

基础知识

  目前已知有如下的初始化方式:

int x();
int y = ;
int z{};
int z = {}; // the same as above

  在以“=”初始化的过程中没有调用赋值运算,如下例所示:

Widget w1; // default ctor
Widget w2 = w1; // copy ctor
w1 = w2; // assignment, operator =

  还可以用来初始化:

class Widget {
int x{}; // fine
int y = ; // fine
int z(); // error
}; std::atomic<int> ai1{}; // fine
std::atomic<int> ai2(); // fine
std::atomic<int> ai3 = ; // error

  在构造函数中,()与{}在不含有的std::initializer_list的时候意义相同。但是如果出现std::initializer_list,则使用{}初始化语法的时候更倾向调用重载过后的函数。甚至那些拷贝和移动构造函数也会被劫持,例如:

class Widget {
public:
Widget(int i, bool b);
Widget(int i, double d);
Widget(std::initializer_list<long double> il);
operator float() const;
}; Widget w5(w4); // copy ctor
Widget w6{w4}; // w4 -> float -> initializer_list<long double>

  std::initializer_list构造函数太强烈, 以致最优的匹配函数不是它,也会因缩窄匹配而错误:

Widget(std::initializer_list<bool> il);

Widget w{, 5.0}; // error, narrowing conversions

  只有在不能通过转换匹配的情况下,编译器才查找原来的函数:

Widget(std::initializer_list<std::string> il);

Widget w{, 5.0}; // OK

  在空值的情况下:

Widget w1; // default ctor
Widget w2{}; // default ctor
Widget w3(); // most vexing parse! function

总结

  • {}初始化时最多使用的初始化语法,它不能进行缩窄转换(narrowing conversion),并且对一些令人烦恼的解析(most vexing parse)免疫
  • 在构造函数重载解析过程中,{}初始化优先匹配std::initializer_list,即使其他构造函数更匹配
  • 使用()或者{}的方式创建std::vector<numeric type>会有很大的不同
  • 在模板中选择()或{}方式创建对象是一个挑战
上一篇:Markdown语法大全


下一篇:【codeforces 752F】Santa Clauses and a Soccer Championship