从初始化列表转换为“A”将使用显式构造函数“A::A(int)”

mal*_*lat 10 c++ gcc-warning c++11

我正在尝试将旧的 C++03 代码库迁移到 C++11。但我无法理解 gcc 在以下情况下警告我的内容:

\n
% g++ -std=c++03 t.cxx\n% g++ -std=c++11 t.cxx\nt.cxx: In function \xe2\x80\x98int main()\xe2\x80\x99:\nt.cxx:8:21: warning: converting to \xe2\x80\x98A\xe2\x80\x99 from initializer list would use explicit constructor \xe2\x80\x98A::A(int)\xe2\x80\x99\n    8 | int main() { B b = {}; }\n      |                     ^\nt.cxx:8:21: note: in C++11 and above a default constructor can be explicit\n
Run Code Online (Sandbox Code Playgroud)\n
struct A {\n  explicit A(int i = 42) {}\n};\nstruct B {\n  A a;\n};\n    \nint main() {\n  B b = {};\n  return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我在这里想做的只是基本的零初始化。这对于 C++03 似乎是合法的,但我无法理解如何在 C++11 中表达等价物。

\n
\n

作为参考,我正在使用:

\n
% g++ --version\ng++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0\n
Run Code Online (Sandbox Code Playgroud)\n

use*_*570 8

由于下面解释的原因,给定的程序格式不正确。

C++20

B是一个聚合体。由于您没有显式初始化a,因此dcl.init.aggr#5适用:

  1. 对于非联合聚合,每个不是显式初始化元素的元素都按如下方式初始化:

5.2 否则,如果元素不是引用,则从空初始化器列表([dcl.init.list]) 复制初始化该元素。

这意味着它a是从空的初始值设定项列表复制初始化的。换句话说,就好像我们在写:

A a = {}; // not valid see reason below
Run Code Online (Sandbox Code Playgroud)

现在我们进入dcl.init.list#3.5

否则,如果初始值设定项列表没有元素并且 T 是具有默认构造函数的类类型,则该对象是值初始化的

这意味着该对象将被初始化。

现在进行值初始化

对 T 类型的对象进行值初始化意味着:

  • 如果 T 是(可能是 cv 限定的)类类型 ([class]),则
    • 如果 T 没有默认构造函数 ([class.default.ctor]) 或用户提供或删除的默认构造函数,则该对象是默认初始化的

所以我们进入默认初始化

如果 T 是一个(可能是 cv 限定的)类类型 ([class]),则考虑构造函数。枚举适用的构造函数 ([over.match.ctor]),并通过重载选择初始化程序 () 的最佳构造函数分辨率([over.match])。使用空参数列表调用如此选择的构造函数来初始化对象。

最后来自over.match.ctor

当类类型的对象被直接初始化、从相同或派生类类型 ([dcl.init]) 的表达式复制初始化或默认初始化时,重载决策会选择构造函数。对于不在复制初始化上下文中的直接初始化或默认初始化,候选函数是正在初始化的对象的类的所有构造函数。 对于复制初始化(包括复制初始化上下文中的默认初始化),候选函数是该类的所有转换构造函数 ([class.conv.ctor])。 参数列表是初始化器的表达式列表或赋值表达式。

这意味着只有转换因子才是候选者。并且由于A::A(int)是显式的,所以它不是转换因子,因此候选集是空的并且program( A a ={};)是格式错误的。


从本质上讲,失败的原因是A a = {};格式不正确。


解决方案

为了解决这个问题,我们可以将A{}orA{0}作为列表中的初始化器传递,如下所示:

B b = { A{} };  //ok now 
B c = { A{0} }; //also ok
Run Code Online (Sandbox Code Playgroud)

工作演示


笔记

A a{};请注意,另一方面,写作格式良好,因为这是一个直接初始化上下文,因此它是direct-list-initialization