簡體   English   中英

為什么使用帶括號的初始化程序列表時首選std :: initializer_list構造函數?

[英]Why is the std::initializer_list constructor preferred when using a braced initializer list?

考慮代碼

#include <iostream>

class Foo
{
    int val_;
public:
    Foo(std::initializer_list<Foo> il)
    {
        std::cout << "initializer_list ctor" << std::endl;
    }
    /* explicit */ Foo(int val): val_(val)
    {
        std::cout << "ctor" << std::endl;
    };
};

int main(int argc, char const *argv[])
{
    // why is the initializer_list ctor invoked?
    Foo foo {10}; 
}

輸出是

ctor
initializer_list ctor

據我了解,值10隱式轉換為Foo (第一個ctor輸出),然后初始化構造函數啟動(第二個initializer_list ctor輸出)。 我的問題是為什么會這樣? 標准構造函數Foo(int)更好嗎? 即,我希望該代碼段的輸出僅為ctor

PS:如果我將構造函數Foo(int)標記為explicit ,則Foo(int)是唯一調用的構造函數,因為現在無法將整數10隱式轉換為Foo

§13.3.1.7[over.match.list] / p1:

當非聚合類類型T被列表初始化(8.5.4)時,重載解析會分兩個階段選擇構造函數:

  • 最初,候選函數是類T的初始化器列表構造函數(8.5.4),參數列表由作為單個參數的初始化器列表組成。
  • 如果找不到可行的初始化器列表構造函數,則再次執行重載解析,其中候選函數是T類的所有構造器,並且參數列表由初始化器列表的元素組成。

如果初始化列表中沒有元素,並且T具有默認構造函數,則省略第一階段。 在復制列表初始化中,如果選擇了explicit構造函數,則初始化的格式不正確。

只要有可行的initializer-list構造函數,當使用list-initialization並且initializer列表至少包含一個元素時,它將勝過所有非initializer-list構造函數。

關於初始化程序列表的n2100建議書詳細說明了使序列構造函數(它們稱為采用std::initializer_lists構造std::initializer_lists )優先於常規構造函數的決定。 有關詳細討論,請參見附錄B。 結論中總結如下:

11.4結論

那么,我們如何在其余兩個選擇之間做出決定(“歧義”和“序列構造函數優先於普通構造函數”)? 我們的建議優先考慮序列構造函數,因為

  • 在所有構造函數中尋找歧義會導致過多的“誤報”; 也就是說,顯然無關的構造函數之間發生沖突。 請參閱下面的示例。
  • 消歧本身就容易出錯(以及冗長)。 請參閱第11.3節中的示例。
  • 對同類列表中的每個元素使用完全相同的語法非常重要–應該對普通構造函數(沒有規則的參數模式)進行歧義消除。 請參閱第11.3節中的示例。 誤報的最簡單示例是默認構造函數:

誤報的最簡單示例是默認構造函數:

 vector<int> v; vector<int> v { }; // potentially ambiguous void f(vector<int>&); // ... f({ }); // potentially ambiguous 

可以考慮沒有成員的初始化在語義上與默認初始化不同的類,但是與那些在語義上相同的更為常見的情況相比,我們不會使該語言復雜化以為這些情況提供更好的支持。

優先考慮序列構造函數,可以將參數檢查分成更多可理解的塊,並提供更好的局部性。

 void f(const vector<double>&); // ... struct X { X(int); /* ... */ }; void f(X); // ... f(1); // call f(X); vector's constructor is explicit f({1}); // potentially ambiguous: X or vector? f({1,2}); // potentially ambiguous: 1 or 2 elements of vector 

在這里,優先考慮序列構造函數可以消除X的干擾。為f(1)選擇X是該問題的一種變體,如第3.3節所示。

整個初始化程序列表是用來啟用列表初始化的,如下所示:

std::vector<int> v { 0, 1, 2 };

考慮一下情況

std::vector<int> v { 123 };

這樣做是為了用一個值為123的元素而不是值為零的123元素初始化向量。

要訪問其他構造函數,請使用舊語法

Foo foo(10);

暫無
暫無

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

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