2014-07-13 58 views
7

書草案Effective C++11斯科特邁爾斯指出:`Object obj(args ...)`和`Object obj {args ...}`有什麼區別?

區分()和{}創建對象

什麼Object obj(args...)Object obj{args...}之間的區別是什麼時候?爲什麼斯科特這麼說。

更新:

問題How to use C++11 uniform initialization syntax?詢問怎麼了,這個問題是問爲什麼。

UPDATE2:

我發現下面的鏈接是有益的,完全回答了這個問題:

https://softwareengineering.stackexchange.com/questions/133688/is-c11-uniform-initialization-a-replacement-for-the-old-style-syntax

+0

可能重複的[如何使用C++ 11均勻初始化語法?](http://stackoverflow.com/questions/7612075/how-to-use-c11-uniform-initialization-syntax) –

+0

@MattMcNabb,這個問題問如何,這個問題問爲什麼。 – xmllmx

+5

這個問題不問「爲什麼」,另一個問題涉及統一初始化的作用。 –

回答

5

什麼Object obj(args...)Object obj{args...}之間的區別?

首先是直接初始化而第二個是直接列表初始化。這在兩個不同的部分中提到:

第8.5節/ 16 [dcl.init]

發生在形式

T x(a); 
T x{a}; 

以及在new表達式(初始化5.3.4),static_cast表達式(5.2.9),函數表示式類型轉換(5.2.3),以及基本成員初始化程序(12.6.2)被稱爲直接初始化

§8.5.4/ 1 [dcl.init.list]

列表初始化是從支撐-INIT列表對象或參考的初始化。這種初始化器被稱爲初始化器列表,並且列表的逗號分隔的子句被稱爲初始化器列表的元件。初始化程序列表可能爲空。 列表初始化可以發生在直接初始化或複製初始化上下文中;在直接初始化上下文中的列表初始化被稱爲直接列表初始化並且複製初始化上下文中的列表初始化被稱爲複製列表初始化


有兩個之間的一些區別:

  • 如果正在構建的類型有一個構造函數的initializer_list說法,直接列表初始化永遠青睞的是構造函數。其他構造函數僅在initializer_list構造函數不可用時纔會被考慮。 §13.3.1.7/ 1 [over.match.list]

  • 直接一覽初始化不允許參數列表內縮小轉換。 §8.5.4/ 3 [dcl.init.list]

  • 如果被初始化的類型是一個聚集,直接一覽初始化將執行集合初始化。 §8.5.4/ 3 [dcl.init.list]

  • 一個支撐-INIT列表是從左至右的元件的評價的順序。 §8.5.4/ 4 dcl.init.list]

  • 您可以通過使用直接列表初始化

 

struct foo{}; 
    struct bar 
    {  
    bar(foo const&) {} 
    }; 

    bar b1(foo()); // most vexing parse 
    bar b2(foo{}); // all 3 of the following construct objects of type bar 
    bar b3{foo()}; 
    bar b4{foo{}}; 
1

什麼是obj對象之間的差異(參數...)和對象OBJ {ARGS ...}?爲什麼斯科特這麼說。

的區別是,前者情況下,參數計算順序是未測序(即未指定的),但在後一種情況下,順序爲從左向右(即它們出現)。

從$ 5.2.2/8下面的文本[expr.call](n3690)與Object(args...)形式涉及:

後綴表達式的和的參數的評價都是未測序相對於一個另一個。參數評估的所有副作用在輸入函數之前進行排序(見1.9)。

而且從$ 8.5.4/4文本[dcl.init.list(n3690)與Object{args...}形式的交易:

在一個支撐,初始化列表的初始化列表中, 初始化子句,包括從包擴展 (14.5.3)導致的任何結果,都是,按它們出現的順序評估。也就是 在給定的 初始化子句關聯的每個值計算和副作用在每個值計算和 副作用與在初始化程序列表的逗號分隔列表 之後的任何初始化子句關聯。 [注意:無論 初始化的語義如何,此 評估順序都成立;例如,當 初始化程序列表的元素被解釋爲構造函數調用的參數 時,即使通常在調用的參數 上沒有排序約束,也適用。 - 注完]

那麼這意味着這樣的:

int f() { static int i = 10; return ++i; } //increment the static int! 

Object obj(f(), f()); //is it obj(11,12) or obj(12,11)? Unspecified. 

Object obj{f(), f()}; //it is obj(11,12). Guaranteed. 

注意GCC (4.7.0 and 4.7.2) have a bug because of which {} form doesn't work the way it should。我不確定它是否在當前版本中修復。

希望有所幫助。

2

Object obj(args...)Object{args...}的行爲取決於在Object中定義的構造函數。

看看下面的例子:

#include <iostream> 
#include <initializer_list> 

struct A 
{ 
    A(int a, int b) {std::cout << "Came to A::A()\n";} 
}; 

struct B 
{ 
    B(int a, int b) {std::cout << "Came to B::B(int, int)\n";} 
    B(std::initializer_list<int> in) {std::cout << "Came to B::B(std::initializer_list<int>)\n";} 
}; 

int main() 
{ 
    A a1(10, 20); // Resolves to A(int, int) 
    A a2{10, 20}; // Resolves to A(int, int) 
    A a3{30};  // Does not resolve to anything. It's a compiler error. 

    B b1(10, 20); // Resolves to B(int, int) 
    B b2{10, 20}; // Resolves to B(std::initializer_list<int>) 
    B b3{30};  // Resolves to B(std::initializer_list<int>) 

} 
1
避免最令人頭痛的解析

Object obj(args ...)和Object obj {args ...}之間的區別是什麼?

{args ...}會比其他合法候選人更喜歡帶initializer_list的構造函數。

std::vector<int> v(10); // vector of size 10 
std::vector<int> v{10}; // vector initialized with a single element, (int) 10 

另一方面,你放棄了隱含的縮小。

std::vector<int> v(10.5); // vector of size 10 
std::vector<int> v{10.5}; // illegal - no compile 
std::vector<float> v{10.5}; // vector initialized with a single element, (float) 10.5 
相關問題