转换为‘ a’从初始化器列表中将使用显式构造函数‘ a :: A(int)’

发布于 2025-02-09 17:06:26 字数 830 浏览 0 评论 0原文

我正在尝试将旧的C ++ 03代码库迁移到C ++ 11。但是我无法理解在下种情况下警告我的GCC是什么:

% g++ -std=c++03 t.cxx
% g++ -std=c++11 t.cxx
t.cxx: In function ‘int main()’:
t.cxx:8:21: warning: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(int)’
    8 | int main() { B b = {}; }
      |                     ^
t.cxx:8:21: note: in C++11 and above a default constructor can be explicit
struct A {
  explicit A(int i = 42) {}
};
struct B {
  A a;
};
    
int main() {
  B b = {};
  return 0;
}

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


作为参考,我正在使用:

% g++ --version
g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0

I am trying to migrate an old C++03 codebase to C++11. But I fail to understand what gcc is warning me about in the following case:

% g++ -std=c++03 t.cxx
% g++ -std=c++11 t.cxx
t.cxx: In function ‘int main()’:
t.cxx:8:21: warning: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(int)’
    8 | int main() { B b = {}; }
      |                     ^
t.cxx:8:21: note: in C++11 and above a default constructor can be explicit
struct A {
  explicit A(int i = 42) {}
};
struct B {
  A a;
};
    
int main() {
  B b = {};
  return 0;
}

All I am trying to do here is a basic zero initialization. It seems to be legal for C++03, but I fail to understand how to express the equivalent in C++11.


For reference, I am using:

% g++ --version
g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

赤濁 2025-02-16 17:06:26

由于下面的原因,给定的程序是

C ++ 20

b汇总。由于您不是明确初始化a dcl.init.aggr#5 适用:

  1. 对于非工会骨料,不是显式初始化元素的每个元素的初始化,如下所示:

5.2否则,如果元素不是参考,则该元素是从空的初始化器列表中进行了复制([dcl.init.list])。

这意味着a从一个空的初始化器列表中复制初始化。换句话说,就像我们在写作一样:

A a = {}; // not valid see reason below

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

否则,如果初始化器列表没有元素,而t是具有默认构造函数的类类型,则该对象为 value-initialized

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

现在到值初始化

to-initialize t type t type的对象表示:

  • 如果t是(可能是CV qualified)类类型([class]),则
    • 如果t没有默认构造函数([class.default.ctor])或用户提供或删除的默认构造函数,则该对象为 default-initialialized ;

因此,我们进入默认初始化

如果t是(可能是CV合格的)类类型([[class]),则考虑构造函数。通过超载分辨率([over.match])选择一个初始化器()。
因此,选择的构造函数被称为“空参数”列表以初始化对象。

最后来自 over.match.ctor.ctor

当类型的对象被直接定义时,从相同或派生类类型的表达式([dcl.Init])或默认initialized Initialized Ordroad分辨率选择构造函数时。
对于不在拷贝性定位的上下文中,候选函数的直接启动或默认限制是所有要初始化对象类的构造函数。
用于复制定位化(包括在复制定位化的上下文中的默认初始化),候选函数是该类别的所有转换构造函数([class.conv.ctor])。
参数列表是初始化器的表达列表或分配表达。

这意味着只有转换CTOR才是候选人。而且由于a :: a(int)是明确的,因此它不是转换的ctor,因此候选人集为空,并且程序(a a a = {};)是不构建的。


本质上,失败的原因是a a = {};是错误的。


解决此问题的解决方案

,我们可以通过a {}a {0}作为列表中的初始化器,如下所示:

B b = { A{} };  //ok now 
B c = { A{0} }; //also ok

工作演示


注意,另一方面,编写a a {};,因为这是一个直接的启动上下文,因此它是 direct-list-list-initialization

The given program is ill-formed for the reason(s) explained below.

C++20

B is an aggregate. Since you're not explicitly initializing a, dcl.init.aggr#5 applies:

  1. For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:

5.2 Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).

This means that a is copy initialized from an empty initializer list. In other word, it is as if we're writing:

A a = {}; // not valid see reason below

Now we move onto dcl.init.list#3.5:

Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.

This means that the object will be value initialized.

Now to value initialize:

To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type ([class]), then
    • if T has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted, then the object is default-initialized;

So we move onto default initialize:

If T is a (possibly cv-qualified) class type ([class]), constructors are considered.The applicable constructors are enumerated ([over.match.ctor]), and the best one for the initializer () is chosen through overload resolution ([over.match]).
The constructor thus selected is called, with an empty argument list, to initialize the object.

Finally from over.match.ctor:

When objects of class type are direct-initialized, copy-initialized from an expression of the same or a derived class type ([dcl.init]), or default-initialized, overload resolution selects the constructor.
For direct-initialization or default-initialization that is not in the context of copy-initialization, the candidate functions are all the constructors of the class of the object being initialized.
For copy-initialization (including default initialization in the context of copy-initialization), the candidate functions are all the converting constructors ([class.conv.ctor]) of that class.
The argument list is the expression-list or assignment-expression of the initializer.

This means that only the converting ctor are candidates. And since A::A(int) is explicit, it is not a converting ctor and thus there the set of candidates is empty and the program(A a ={};) is ill-formed.


Essentially, the reason for the failure is that A a = {}; is ill-formed.


Solution

To solve this, we can pass A{} or A{0} as the initializer inside the list as shown below:

B b = { A{} };  //ok now 
B c = { A{0} }; //also ok

Working demo.


Note

Note that writing A a{}; on the other hand is well-formed as this is a direct-initialization context and so it is direct-list-initialization.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文