簡體   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