C++11: "= {}"的类内初始化不适用于显式构造函数

标签 c++ c++11 initializer-list explicit-constructor in-class-initialization

在 C++11 中,我们可以使用“brace-or-equal-initializer”(标准中的词)进行类内初始化,如下所示:

struct Foo
{
  /*explicit*/ Foo(int) {}
};

struct Bar
{
  Foo foo = { 42 };
};

但是如果我们取消注释 explicit,它就不再编译了。 GCC 4.7 和 4.9 是这样说的:

error: converting to ‘Foo’ from initializer list would use explicit constructor ‘Foo::Foo(int)’

我觉得这很令人惊讶。这段代码不编译真的是C++11标准的本意吗?

删除 = 修复它:Foo foo { 42 }; 但我个人觉得这很难向习惯于使用 表单的人解释= 几十年了,由于标准提到了“大括号或等号初始化器”,因此旧的好方法在这种情况下不起作用并不明显。

最佳答案

我无法解释这背后的基本原理,但我可以重复显而易见的事情。

I found this surprising. Is it really the intention of the C++11 standard that this code doesn't compile?

§13.3.1.7

In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.


Removing the = fixes it: Foo foo { 42 }; but I personally find this harder to explain to people who have been used to the form with = for decades, and since the standard refers to a "brace-or-equal-initializer" it's not obvious why the good old way doesn't work in this scenario.

Foo foo { 42 }direct initialization , 而等号(带大括号)使它成为 copy-list-initialization .另一个答案的原因是因为 copy-initialization 的编译失败(不带大括号的等号),那么它也因复制列表初始化而失败也就不足为奇了,但这两个失败的原因不同。

cppreference:

Direct-initialization is more permissive than copy-initialization: copy-initialization only considers non-explicit constructors and user-defined conversion functions, while direct-initialization considers all constructors and implicit conversion sequences.

还有他们在 explicit specifier 上的页面:

Specifies constructors and (since C++11) conversion operators that don't allow implicit conversions or copy-initialization.

另一方面,对于复制列表初始化:

T object = {arg1, arg2, ...}; (10)

10) on the right-hand-side of the equals sign (similar to copy-initialization)

  • Otherwise, the constructors of T are considered, in two phases:

    • If the previous stage does not produce a match, all constructors of T participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed. If this stage produces an explicit constructor as the best match for a copy-list-initialization, compilation fails (note, in simple copy-initialization, explicit constructors are not considered at all)

What could go wrong if copy-list-initialization allowed explicit constructors? 中所述,编译失败,因为选择了显式构造函数但不允许使用。

关于C++11: "= {}"的类内初始化不适用于显式构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26137325/

相关文章:

c++ - AVL树奇怪的行为

c++ - OpenGL C++ 制作三角形

c++ - 继承构造函数仅部分起作用

multithreading - 在 Linux 2.6+ 中替换系统调用(syscalls)

c++ - 在编译时将 initializer_list<T> 转换为 initializer_list<vector<T>>

c++ - 为什么在 C++14 中对数组的初始化仍然需要双括号?

c++ - 为什么初始化列表允许在 C++ 中缩小类型?

c++ - 用于 C++ 开发的 Xcode 5 插件

c++ - 为每个线程重定向标准输出/标准错误

c++ - 视觉 C++ : forward an array as a pointer