gpt4 book ai didi

c++ - 列出聚合的初始化 : when can it invoke copy constructor?

转载 作者:可可西里 更新时间:2023-11-01 18:31:02 27 4
gpt4 key购买 nike

考虑以下代码:

struct A {
int x;
};

int main() {
A a;
A b{a};
}

这个程序在 C++11 标准下是否良构?在我的 N3797 拷贝中它说

8.5.4 List initialization [dcl.init.list]

3: List-initialization of an object or reference of type T is defined as follows:
- If T is an aggregate, aggregate initialization is performed (8.5.1).
- Otherwise, if T is a specialization of std::initializer_list<E>, ...
- Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen using overload resolution. If a narrowing conversion is required to convert any of the types, the program is ill-formed.
- Otherwise, if the initializer list has a single element of type E and either T is not a reference type or it is reference-related to E, the object or reference is initialized from that element; if a narrowing conversion is required to convert the element to T, the program is ill-formed.
- Otherwise, if T is a reference type, a pr-value temporary of the type reference by T is copy-list-initialized or direct-list-initialized, depending on the kind of initialization for the reference, and the reference is bound to that temporary.
- Otherwise, if the initializer list has no elements, the object is value-initialized.
- Otherwise, the program is ill-formed.

这个例子的要点是,类型是一个聚合,但是列表初始化应该调用复制构造函数。在 gcc 4.8gcc 4.9 ,在 C++11 标准下,它失败了:

main.cpp: In function ‘int main()’:
main.cpp:7:8: error: cannot convert ‘A’ to ‘int’ in initialization
A b{a};
^

并说A is not convertible to int或类似的,因为聚合初始化失败。在 gcc 5.4 ,它在 C++11 标准下运行良好。

关于 clang你会得到类似的错误 clang-3.5 , 3.6 , 它开始工作于 clang-3.7 .

我知道它在 C++14 标准下是良构的,并且在缺陷报告中提到了它 here .

但是,我不明白为什么这被认为是标准中的缺陷。

标准写的时候,

“如果 X,则执行 foo 初始化。否则,如果 Y,则执行 bar 初始化,....否则,程序格式错误。”,

这是否意味着如果X成立,但无法执行 foo 初始化,那么我们应该检查是否 Y持有,然后尝试栏初始化?

这将使示例工作,因为当聚合初始化失败时,我们不匹配 std::initializer_list ,我们匹配的下一个条件是“T 是类类型”,然后我们考虑构造函数。

请注意,这确实似乎是它在这个修改后的示例中的工作方式

struct A {
int x;
};

int main() {
A a;
const A & ref;
A b{ref};
}

在 C++11 和 C++14 标准中,所有相同的编译器都以与前面示例相同的方式处理它。但似乎 CWG 缺陷记录中修改后的措辞不适用于此案例。内容如下:

If T is a class type and the initializer list has a single element of type cv T or a class type derived from T, the object is initialized from that element.

http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1467

但在第二个代码示例中,初始化列表在技术上包含 const T & .所以我不知道它是如何工作的,除非在聚合初始化失败后,我们应该尝试构造函数。

我错了吗?聚合初始化失败后是否不应该尝试构造函数?

这是一个相关的例子:

#include <iostream>

struct B {
int x;

operator int() const { return 2; }
};

int main() {
B b{1};
B c{b};
std::cout << c.x << std::endl;
}

clang-3.6 , gcc-4.8 , gcc-4.9 , 它打印 2 ,并在 clang-3.7 , gcc-5.0它打印 1 .

假设我错了,并且在 C++11 标准中,聚合的列表初始化应该是聚合初始化而不是别的,直到引入缺陷报告中的新措辞,这是否是一个错误发生即使我选择 -std=c++11在较新的编译器上?

最佳答案

When the standard writes,

"If X, foo-initialization is performed. Otherwise, if Y, bar-initialization is performed, .... Otherwise, the program is ill-formed.",

doesn't this mean that if X holds, but foo-initialization cannot be performed, then we should check if Y holds, and then attempt bar-initialization?

不,它没有。把它想象成实际的代码:

T *p = ...;
if(p)
{
p->Something();
}
else
{ ... }

p 不是 NULL。这也不意味着它是一个有效的指针。如果 p 指向一个被销毁的对象,p->Something() 失败不会导致您跳到 else。您有机会在这种情况下保护通话。

所以你会得到未定义的行为。

这里也是一样。如果 X,则执行 A。这并不意味着如果 A 失败会发生什么;它告诉你去做。如果做不到……你就完蛋了。

关于c++ - 列出聚合的初始化 : when can it invoke copy constructor?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39005700/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com