2013-05-31 7 views
10

Was ist der Unterschied zwischenUniform Initialisierung Syntax Unterschied

A a{ A() }; 

tun und

A a(A{}); 

die Most Vexing Parse zu vermeiden? Wann sollte ich einen bestimmten verwenden?

+2

In dieser besonderen Situation wäre die einfachste Option 'A a;', oder? Wenn ich das nicht falsch verstehe, macht die von Ihnen vorgeschlagene Syntax nur Sinn, wenn das Temporär, das Sie an den Konstruktor von 'A' übergeben wollen, von einem anderen Typ als' A' ist, richtig? I.e. 'A a {B()};'. – jogojapan

Antwort

13

Die beiden Syntaxen sind in den meisten Situationen gleichwertig, und welche man wählt, ist meistens eine Frage des Geschmacks. Wenn Sie in einheitliche Initialisierung sind, würde ich tun vorschlagen:

A a{ A{} }; 

Andernfalls allein Klammern verwendet werden können, eindeutig zu machen:

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

Hinweis, dass es eine Situation (sehr unwahrscheinlich ist, muss ich sagen,) wo die zwei in Ihrer Frage gezeigten Formen nicht gleichwertig sind. Wenn Ihre Klasse A einen Konstruktor hat, der eine initializer_list<A> nimmt, wird dieser Konstruktor über den Copykonstruktor begünstigt werden, wenn die Klammern verwendet:

#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" 
} 

Die obige Differenz wird in diesem live example gezeigt.

+2

Eigentlich druckt der erste * nicht "copy-ctor" für mich. Ich denke, seine Kopie Elision. –

+0

@MemyselfandI: Huh, richtig, der Compiler ist die Kopie - aber konzeptionell wird der Kopierkonstruktor ausgewählt –

+0

Funktioniert copy-elision nur, wenn Optimierungen aktiviert sind? –

9

In den meisten Fällen sind sie gleichwertig, aber A a{ A() }; einen std::initializer_list Konstruktor bevorzugen, wenn eine vorhanden ist, während A a(A{}); eine Bewegung/Copykonstruktor bevorzugen.

Wenn das Konstrukt einen move/copy -Konstruktor aufruft, kann die Konstruktion des neuen Objekts weggelassen werden, aber das ist für einen std::initializer_list Konstruktor nicht möglich.

Keine Syntax wird jemals als Funktionsdeklaration geparst, so dass beide die am meisten ärgerliche Analyse vermeiden.

#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" 
}