2013-05-31 77 views
10

什麼做統一初始化語法區別

A a{ A() }; 

之間的差異,

A a(A{}); 

避免Most Vexing Parse?我應該什麼時候使用特定的一個?

+2

在這種特殊情況下,最簡單的選擇是'A a;',對吧?如果我不誤解這一點,那麼當你想要傳遞給'A'的構造函數的類型與'A'類型不同時,你所建議的語法纔有意義,對嗎?即'A a {B()};'。 – jogojapan

回答

13

這兩種語法在大多數情況下是等價的,哪一種選擇主要是品味問題。如果你到統一的初始化,我建議做:

A a{ A{} }; 

否則,圓括號單獨可以用來消除:

A a((A())); // This can't be parsed as a function declaration 

注意,有一種情況(可能性非常小,我必須說)在你的問題中顯示的兩種形式不相同。如果您A類有一個構造函數的initializer_list<A>,該構造將優於拷貝構造函數當使用大括號:

#include <initializer_list> 
#include <iostream> 

struct A 
{ 
    A() { } 
    A(std::initializer_list<A> l) { std::cout << "init-list" << std::endl; } 
    A(A const& a) { std::cout << "copy-ctor" << std::endl; } 
}; 

int main() 
{ 
    A a(A{}); // Prints "copy-ctor" (or nothing, if copy elision is performed) 
    A b{A()}; // Prints "init-list" 
} 

上述差異在此live example所示。

+2

其實,第一個*不會爲我打印「copy-ctor」。我認爲它的複製elision。 –

+0

@MemyselfandI:對,編譯器正在刪除拷貝 - 但從概念上說,拷貝構造函數被選中 –

+0

複製刪除僅在優化啓用時纔會發生? –

9

在大多數情況下它們是等效的,但A a{ A() };將更喜歡std::initializer_list構造函數(如果存在的話),而A a(A{});將偏好移動/複製構造函數。

當構造器最終調用移動/複製構造函數時,可以省略新對象的構造,但對於std::initializer_list構造函數來說這是不可能的。

兩種語法都不會被解析爲函數聲明,所以都避免了最棘手的解析。

#include <iostream> 
#include <initializer_list> 
struct A { 
    A() { 
     std::cout << "A()\n"; 
    } 
    A(A&&) { 
     std::cout << "A(A&&)\n"; 
    } 
    A(std::initializer_list<A>) { 
     std::cout << "A(std::initializer_list<A>)\n"; 
    } 
}; 
int main() 
{ 
    {A a{ A() };} // Prints "A()\n" "A(std::initializer_list<A>)\n" 
    {A a(A{});} // Prints "A()\n" and *possibly* 
        // (depending on copy elision) "A(A&&)\n" 
}