大括号和圆括号中的初始值设定符-来自现代有效C++中的项7



在本书第7章第7项中"有效的现代Cpp";,讨论了创建对象时((和{}之间的差异。然而,当我编译并运行本章中列出的一些代码时,我发现代码的行为与注释所描述的不同。我必须指出,我用于测试的代码是由我编写的,因此与书中的原始代码不完全相同,但它更简单,足以涵盖我的观点。我很肯定,这些差异不会是我遇到问题的原因。

PDF格式的书中感兴趣的内容的位置是第53页第7项。

在本页末尾,对代码";小部件w6{w4}&";,说";使用大括号,调用std::initializer_list ctor(w4转换为float,float转换为long double("。然后,我在下面写了我的代码,只是为了进行定期验证,直到我看到代码的输出,我才想到会有任何异常。

#include <iostream>
using namespace std;
class Widget {
public:
Widget(int i) : _i(i){
cout << "call to Widget(int i)" << endl;
}
Widget(Widget& w) {
_i = w._i;
cout << "call to Widget(Widget& w)" << endl;
}
Widget(initializer_list<int> il) {
if (il.size() > 0) {
_i = *(il.begin());
}
cout << "call to Widget(initializer_list<int> il)" << endl;
}
void print_info() {
cout << "_i: " << _i << endl;
}
operator int() const {
// return a fixed value just for testing
return 100;
}
private:
int _i;
};
// this is the testbed
int main() {
Widget w1{10, 5};
w1.print_info();
cout << "----------------------------------------" << endl;
Widget w2{{w1}};
w2.print_info();
cout << "----------------------------------------" << endl;
Widget w3{w1};
w3.print_info();
return 0;
}

代码的输出类似

~/CppTest/move_construct  g++ -std=c++17 -o run test.cpp                                    ✔  11:49:11
~/CppTest/move_construct  ./run                                                             ✔  11:49:26
call to Widget(initializer_list<int> il)
_i: 10
----------------------------------------
call to Widget(initializer_list<int> il)
_i: 100
----------------------------------------
call to Widget(Widget& w)
_i: 10

正如你所看到的,w2的初始化使用支撑初始化,w1被包裹在另一层支撑中,其行为与书中的评论完全相同。但是w3是使用单层大括号初始化的,它只是复制构建的。

我不知道这是由编译器的发展、cpp标准还是我忽略的某种编译器配置引起的。我使用的编译器的信息是:

Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: x86_64-apple-darwin21.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

谢谢并期待您的回答。

在编写本书时,std::initializer_list构造函数应该优先于副本构造函数,这是正确的。

然而,随后CWG 1467对规则进行了更改,结果是首选复制构造函数。

然而,这可能只是一个意外的副作用,因为规则只是用来修复聚合类的行为,所以CWG 2137再次修改了规则,大意是std::initializer_list构造函数将是首选的,就像原始行为一样。

您似乎正在使用Clang,它恰好还没有实现后一个缺陷报告,请参阅此打开的错误报告。

因此,最终这本书仍然是正确的,但编译器没有跟上规则的变化。

GCC产生预期输出。有趣的是,MSVC在试图编译代码时有一个内部编译器错误(也是一个错误(:https://godbolt.org/z/TKcEzn1be

最新更新