簡體   English   中英

復制構造函數與 std::initializer_list 構造函數

[英]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 localVariableNamethrow localVariableNamecatch(TypeName)如果 catch 與拋出的內容匹配。 這種情況顯然不是這些,所以它不符合常規省略的條件。

暫無
暫無

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

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