繁体   English   中英

大括号和圆括号中的初始化器 - 来自 Modern Effective C++ 中的第 7 项

[英]Initializer in braces and parentheses - From Item 7 in Modern Effective C++

在《Effective Modern Cpp》一书的Chapter7,Item 7中,讨论了创建对象时()和{}的区别。 然而,当我编译并运行本章中列出的一些代码时,我发现代码的行为与注释描述的不同。 我必须指出,我用于测试的代码是我编写的,因此与书中的原始代码不完全相同,但它更简单,足以涵盖我的观点。 而且我非常肯定,差异不会是我遇到的问题的原因。

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

在本页末尾,对代码“Widget w6{w4};”的注释说“使用大括号,调用 std::initializer_list ctor(w4 转换为 float,float 转换为 long double)”。 然后,我在下面写了我的代码只是为了定期验证,直到我看到代码的 output 之前,我并没有期待任何异常。

#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;
}

代码的 output 就像

 ~/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 产生预期的 output。有趣的是,MSVC 在尝试编译您的代码时有一个内部编译器错误(所以也是一个错误): https://godbolt.org/z/TKcEzn1be

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM