[英]Copy constructor vs std::initializer_list constructor
想象一下,我們有:
struct S {
struct S {
S() { printf("%s\n", __PRETTY_FUNCTION__); }
S(const S&) { printf("%s\n", __PRETTY_FUNCTION__); }
S(S&&) { printf("%s\n", __PRETTY_FUNCTION__); }
~S() { printf("%s\n", __PRETTY_FUNCTION__); }
S(std::initializer_list<S>) { printf("%s\n", __PRETTY_FUNCTION__); }
};
當S s2{S{}};
時應該調用哪些構造函數 ? gcc 和 clang 有不同的行為可以嗎?
示例: https://godbolt.org/z/qQxyp5
gcc(主干)output:
S::S()
S::S(std::initializer_list<S>)
S::~S()
S::~S()
clang(主干)output:
S::S()
S::~S()
GCC 在這里是正確的; 列表初始化不允許 C++17 中的復制省略。
如果你做了S s2(S{});
,這將只需要調用S
的默認構造函數,因為[dcl.init]/17.6.1 :
如果初始化表達式是純右值且源類型的 cv 非限定版本與目標的 class 相同 class,則初始化表達式用於初始化目標 ZA8CFDE6331BD59EB2AC96F8911C4B6。 [ 示例:T x = T(T(T())); 調用 T 默認構造函數來初始化 x。 —結束示例]
但是,這只適用於復制初始化和直接初始化。
做S s2{S{}};
是列表初始化,這是它自己完全獨立的初始化形式,有自己的規則。 由於S
不是一個聚合, [dcl.init.list]3.6將接管,它說:
否則,如果 T 是 class 類型,則考慮構造函數。 枚舉適用的構造函數,並通過重載決議([over.match]、[over.match.list])選擇最佳構造函數。
調用構造函數意味着使用一組特定的參數調用特定的 function。 這意味着必須使用純右值S{}
來初始化所選構造函數的參數。 這意味着您必須調用復制/移動構造函數。
也不允許常規的、無保證的省略。 [class.copy.elision]/1 給出了允許省略的 3 種情況: return localVariableName
、 throw localVariableName
和catch(TypeName)
如果 catch 與拋出的內容匹配。 這種情況顯然不是這些,所以它不符合常規省略的條件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.