2013-05-31 11 views
10

Jaka jest różnica między robiUniform inicjalizacji różnica składnia

A a{ A() }; 

, a

A a(A{}); 

uniknąć Most Vexing Parse? Kiedy powinienem użyć konkretnego?

+2

W tej konkretnej sytuacji najprostszą opcją byłoby "A a;", prawda? Jeśli tego nie zrozumiem, sugerowana przez ciebie składnia ma sens tylko wtedy, gdy tymczasowy plik, który chcesz przekazać do konstruktora 'A' jest innego typu niż' A', prawda? To znaczy. 'A a {B()};'. – jogojapan

Odpowiedz

13

Dwie składnie są równoważne w większości sytuacji, a do wyboru należy przede wszystkim kwestia gustu. Jeśli jesteś w jednolitej inicjalizacji Sugerowałbym robi:

A a{ A{} }; 

Inaczej nawiasach sam może być używany do dwuznaczności:

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

odnotować, że istnieje jedna sytuacja (bardzo mało prawdopodobne, muszę powiedzieć,), w przypadku gdy dwa formularze przedstawione w pytaniu nie są równoważne. Jeśli klasa A ma konstruktora, że ​​trwa initializer_list<A>, że konstruktor będzie faworyzowany przez konstruktora kopii kiedy używane są szelki:

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

Powyższa różnica jest pokazana w tym live example.

+2

Właściwie to pierwsze * nie * drukuje "kopia-ctor" dla mnie. Myślę, że jest to eliksir kopiowania. –

+0

@MemyselfandI: Huh, prawda, kompilator usuwa kopię - ale konceptualnie konstruktor kopiowania jest wybierany –

+0

Czy kopiowanie ma miejsce tylko wtedy, gdy włączone są optymalizacje? –

9

W większości przypadków są one równoważne, ale A a{ A() }; woli konstruktor std::initializer_list, jeśli taki jest obecny, natomiast A a(A{}); woli konstruktor ruchu/kopiowania.

Po zakończeniu konstruowania wywołania konstruktora ruchu/kopiowania, konstrukcja nowego obiektu może zostać usunięta, ale nie jest to możliwe dla konstruktora std::initializer_list.

Żadna składnia nigdy nie zostanie zanalizowana jako deklaracja funkcji, więc obie metody unikają najbardziej irytujących analiz.

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