簡體   English   中英

Clang vs GCC vs MSVC - 使用大括號括起初始化列表創建用戶定義類型?

[英]Clang vs GCC vs MSVC - using brace-enclosed initializer list to create user defined type?

正在試驗括號封閉的初始化列表和編譯器似乎行為不同(嗯,這是一個相當新的特性),但是想知道什么應該是正確的行為,特別是如果下面提到的'c3'實際上應該編譯私有的,默認的初始化變量?

int main() {
    struct c1 {
        bool b;
        char c;
        int i;
    };

    auto c1_ = c1{true, '0', 0};
    //clang-3.6 - okay
    //gcc-4.9   - okay
    //vs-2013   - okay

    // ------------------------------------------

    struct c2 {
        bool b;
        char c;
        int i = 0; // with default value
    };

    auto c2_ = c2{true, '0', 0};
    //clang-3.6 - okay
    //gcc-4.9   - error: no matching function for call to ‘c2::c2(<brace-enclosed initializer list>)’
    //vs-2013   - error C2440: '<function-style-cast>' : cannot convert from 'initializer-list' to 'c2'

    auto c2__ = c2{true, '0'};
    //clang-3.6 - okay
    //gcc-4.9   - error: no matching function for call to ‘c2::c2(<brace-enclosed initializer list>)’
    //vs-2013   - error C2440: '<function-style-cast>' : cannot convert from 'initializer-list' to 'c2'

    // ------------------------------------------

    struct c3 {
        bool b;
        char c;
    private:
        int i = 0; // with private default value
    };

    auto c3_ = c3{true, '0'};
    //clang-3.6 - error: no matching constructor for initialization of 'c3'
    //gcc-4.9   - error: no matching function for call to ‘c3::c3(<brace-enclosed initializer list>)’
    //vs-2013   - error C2440: '<function-style-cast>' : cannot convert from 'initializer-list' to 'c3'
}

這是聚合初始化。

定義聚合的C ++ 11段落(n3337,§8.5.1/ 1):

聚合是一個數組或類(第9節),沒有用戶提供的構造函數(12.1),非靜態數據成員(9.2) 沒有大括號或相等的初始值,沒有私有或受保護的非靜態數據成員(子句) 11),沒有基類(第10條),也沒有虛函數(10.3)。

這意味着c2不是聚合而且auto c2_ = c2{true, '0', 0}; 應該在C ++ 11中觸發診斷(並且gcc是正確的)。

然而,使用clang,你似乎在C ++ 14模式下編譯,它刪除了“無支撐或相等的初始化器”限制(n3690,§8.5.1/ 1):

聚合是一個數組或類(第9條),沒有用戶提供的構造函數(12.1),沒有私有或受保護的非靜態數據成員(第11條),沒有基類(第10條),沒有虛函數(10.3) )。

所以, auto c2_ = c2{true, '0', 0}; 在C ++ 14中沒問題。

關於auto c2__ = c2{true, '0'}; ,§8.5.1/ 7(n3690)說:

如果列表中的initializer-clause少於聚合中的成員,那么未明確初始化的每個成員都應從其brace-or-equal-initializer初始化,或者,如果沒有brace-or-equal-initializer ,從空的初始化列表(8.5.4)。

這意味着它是正確的,並且在C ++ 14模式下編譯它是正確的。

c3不是C ++ 11和C ++ 14中的聚合(因為私有成員)所以所有編譯器都拒絕它是正確的。

 auto c2_ = c2{true, '0', 0};
 auto c2__ = c2{true, '0'};

這些在C ++ 14中很好。 類內初始化不會阻止類型在C ++ 14中成為聚合,並且當大括號初始化程序未提供值時,將使用類內值。

auto c3_ = c3{true, '0'};

這是一個錯誤,因為聚合不能有private:protected:成員。 由於它不是聚合,因此只有隱式聲明的默認構造函數。 您可以執行以下操作:

auto c3_ = c3{};

c2不是C ++ 11中的聚合,而是C ++ 14中的聚合。 所以代碼不應該在前者編譯,而應該在后者中編譯。 看起來clang正在用C ++ 14模式編譯。

由於存在private數據成員, c3不是聚合,因此無論標准如何,它都不應編譯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM