【问题标题】:How generic is the {} construction syntax?{} 构造语法的通用性如何?
【发布时间】:2012-09-09 03:18:44
【问题描述】:

talk about initialization lists 中,我理解 Stroustrup 基本上是在说带有花括号的新构造语法 应该 是对所有以前的构造语法的一般替代:

X x1(); // most vexing parse ... doesn't work as intended
X x2(x1);
X x3 = x1;
X x4 = X();

相反,新语法应该被统一使用,作为一种可能的替代品,您可以在每一种情况下使用……再说一次,这是我从他的演讲中得到的核心信息。也许我误解了他。

那么,问题是,这种语法有多通用? 是否有可能永远不要在新的 C++11 代码中使用旧式构造,或者是否存在您必须恢复的情况?


当我遇到以下错误时触发/激发了这个问题,我认为这是编译器中的错误(但我很乐意得到纠正)。

struct X {};

int main() {
  X x;
  X& y{x}; // works with (x)
  X& z{y}; // works with (y)
}

在 g++ 4.7.1 上不能编译,在 ideone's 4.5.1 上也不能编译。

prog.cpp: In function 'int main()':
prog.cpp:5:9: error: invalid initialization of non-const reference of type 'X&' from an rvalue of type '<brace-enclosed initializer list>'
prog.cpp:6:9: error: invalid initialization of non-const reference of type 'X&' from an rvalue of type '<brace-enclosed initializer list>'

请注意,当我将 X 替换为 int 时,它会起作用。

【问题讨论】:

  • 带有花括号的新构造语法不应该是所有以前构造语法的通用替代品。不幸的是,这是一个非常普遍的误解。

标签: c++ constructor c++11 language-lawyer curly-braces


【解决方案1】:

大括号初始化适用于使用初始化程序的任何地方。在某些情况下,您必须使用括号才能访问大括号初始值设定项无法访问的构造函数,但这种情况很少见。

std::vector<int> v(1,1);
std::vector<int> v{1,1};

vector&lt;int&gt; 恰好有一个专门的构造函数,它需要两个 ints,因此尝试构造一个长度为两个 ints 的向量是模棱两可的。模棱两可的构造函数的存在只是为了向后兼容。不应使用任何会与 initializer_list 冲突的构造函数来定义新类。

括号初始化语法优先于 initializer_list 构造函数而不是其他匹配的构造函数这一事实解决了歧义。如果您想解决歧义以支持使用 non-initializer_list 构造函数,那么您不能使用大括号初始化。


Bjarne Stroustrup 写道

只有在 C++11 中才能统一使用 {} 初始化,因此较旧的 C++ 代码使用 () 和 = 初始化。因此,您可能更熟悉 () 和 =。但是,我不知道有任何逻辑理由更喜欢 () 表示法,除非在极少数情况下需要区分使用元素列表和构造函数参数列表进行初始化。

                                                       - C++ 编程语言,第四版 §17.3.2.1


您的示例代码完全合法,应该可以按预期工作。您得到的错误只是 GCC 中的一个错误。 Clang 和 VC++ 2012 都接受代码。

【讨论】:

  • 好点。这可以通过将第二个版本定义为 std::vector&lt;int&gt; v{{1,1}}; 来解决。
  • @bitmask 这些情况实际上并不罕见,因为初始化列表构造函数胜过所有其他构造函数。相关问题here.
  • @bitmask 我认为这不会是一个改进。所要做的就是更改您必须使用的语法,以指示对 initializer_list 构造函数的偏好与否。基本上大括号完全等同于括号,并且在任何一种情况下使用初始化列表都需要一组嵌套的大括号,这意味着语法与数组初始化不一致。
  • @bames53:对,没有考虑数组。
  • 在我看来,我使用 {} 从值列表(包括一个或零值)进行初始化,并使用 () 对所有其他构造函数进行初始化。这解决了所有的歧义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-29
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
相关资源
最近更新 更多