何时使用初始化列表构造函数?

时间:2014-04-02 18:30:02

标签: c++ c++11 initializer-list

在构造函数中使用{}而不是()将允许我在标题中使用特定构造函数初始化类成员,如下所示:

class X {
    private:
        std::vector y{1, 2, 3};
};

但我怎么知道,对于课程Z,我使用Z z{a, b};会调用包含两个参数的构造函数 - Z::Z(int a, int b) - 而不是std::initializer_list

我的意思是std::complex(1, 2)std::complex{1, 2}相同,但std::vector(3)std::vector{3}肯定不是。

我是否应始终使用{}变体或使用(),除非我需要{}

2 个答案:

答案 0 :(得分:8)

这个主题可以涵盖整本书的章节。请参阅Scott Meyers撰写的this recent draft Item中他即将推出的有效现代C ++(为了清晰而重新格式化)的引用:

  

大多数开发人员最终选择一种分隔符作为默认值,   只在必要时使用另一个。

     
      
  • Braces-by-default人们被广泛的适用性所吸引,   他们对narrowing conversions的预防及其避免   C ++的most vexing parse。在某些情况下,这些人理解   (例如,创建具有给定大小和初始元素的std::vector   值),括号是必需的。

  •   
  • 相比之下,走括号的人群将括号视为他们的   默认参数分隔符。他们被它的一致性所吸引   C ++ 98句法传统,它避免了   auto-deduced-a-std::initializer_list problem,以及那些知识   他们的对象创建调用不会是inadvertently waylaid by std::initializer_list constructors。他们有时只承认   大括号会做(例如,当创建具有特定的容器时)   值)。

  •   
     

这两种方法都没有比其他方法更好。我的建议是   选择一个并一致地应用它。

答案 1 :(得分:1)

规则是,如果一个类的构造函数带有initializer_list,并且 braced-init-list 中的元素是可转换的(请记住braced-init-lists确实如此)不允许缩小转换次数到initializer_list的参数类型,然后调用initializer_list的构造函数将始终。否则,编译器将尝试匹配其他构造函数。

如果是空的braced-init-list,则调用默认构造函数,假设一个可访问。

对于初始化,关于圆括号是否应优先于括号,反之亦然,您的问题没有简单的答案。事后看来,vector的构造函数是一个糟糕的设计选择,因为它可以让人意想不到地表现,至少对于没有经验的人来说是非常琐碎的。