2012-01-26 40 views
4
#include <initializer_list> 
#include <iostream> 
using namespace std; 

struct Y {}; 

struct X 
{ 
    X(initializer_list<Y>) { cout << "yay" << endl; } 
    explicit X() { cout << "boo" << endl; } 
}; 

X f() 
{ 
    return {}; 
} 

int main() 
{ 
    f(); 

    return 0; 
} 

這會打印出「boo」。爲什麼不打印出「耶」?initializer_list和默認構造函數重載分辨率

反正是有區分以下兩種結構:

  1. X()
  2. X{}

  1. return X();
  2. return {};

void g(const X&) 
  1. g(X())
  2. g({})

感謝。

+3

它是沒有意義的使用'explicit'使用默認的構造函數,它僅用於構建函數可以被稱爲只有一個參數,禁止隱式類型轉換。例如,'MyObject x = 9;'只有當MyObject有一個非''explicit'cObject'MyObject(int)'時纔可能。在你的例子中,'explicit'被編譯器忽略。 –

+0

是的,我認爲(不正確),它可能會幫助使這種超載按我想要的方式。 –

回答

5

反正是有區分以下兩種結構:

號他們不是不同的結構。

{}構造函數語法的主要目的是引入統一的初始化,以使初始化在任何地方都可以工作。如果它們之間存在差異,則不會一致。

如果你想使用空的初始化列表構造函數,你必須聲明你正在顯式地傳遞一個初始化列表。就像這樣:return initializer_list<Y>{};當然,統一初始化的其他目的之一,就是沒有打出來typenames這麼多,這樣你就可以達到同樣的效果return {{}};

+0

你的直接答案在技術上是正確的(即否)。請注意Mike Seymour的回答「{{}}」和「X({})」。 –

+0

@ user1131467:夠公平的。 –

0

你可能會多一點明確:

return initializer_list<Y>(); 
5

return {};總是使用默認的構造函數,如果有一個。

return X({});return {{}};將從空的初始化列表中構建。

+0

{{}}有用,謝謝。 –

+2

@ user1131467:雖然它可能工作,但它是非常醜陋的...... –

+0

哈哈。這是最美麗的解決方案。 –

1

它使用默認的構造函數,因爲與{}列表初始化,就是要始終值初始化的縮寫形式,忽略其他的構造中,即使它們初始化列表構造。

有無論如何區分以下兩種結構:...

X()總是值初始化,而X{}是,如果X有一個默認的構造函數只值初始化。如果它是一個聚合,則X{}是聚合初始化(遞歸地初始化X的成員{})。如果它只有初始化列表構造和沒有默認構造函數,然後X()是無效的,X{}可以有效

struct A { A(initializer_list<int>); }; 
A a = A{}; // valid 
A b = A(); // invalid 

從本質上講,X{}不取決於什麼X是。但X()始終值初始化。

...或返回X(); vs return {};

一些微妙提...在return {}目標是複製列表初始化,而在return X();第一直接初始化一個X。但即使它是複製列表初始化的,它可以使用explicit默認構造函數,因爲值初始化不關心explicit。但是當你做return {}和您嘗試使用一個明確的非默認構造函數,你就會因錯誤

struct A { 
    explicit A(initializer_list<int>); 
}; 

A f() { return {}; } // error! 

struct B { 
    explicit B(); 
}; 

B g() { return {}; } // OK