2015-07-08 10 views
15

Qual è il comportamento corretto per il seguente programma?Comportamento del compilatore diverso per expression: auto p {make_pointer()};

// example.cpp 

#include <iostream> 
#include <memory> 

struct Foo { 
    void Bar() const { 
    std::cout << "Foo::Bar()" << std::endl; 
    } 
}; 

std::shared_ptr<Foo> MakeFoo() { 
    return std::make_shared<Foo>(); 
} 

int main() { 
    auto p { MakeFoo() }; 
    p->Bar(); 
} 

Quando compilo nel mio Linux RHEL 6.6 workstation, io ottenere i seguenti risultati:

$ g++ -v 
gcc version 5.1.0 (GCC) 
$ g++ example.cpp -std=c++14 -Wall -Wextra -pedantic 
$ ./a.out 
Foo::Bar() 

ma

$ clang++ -v 
clang version 3.6.0 (trunk 217965) 
$ clang++ example.cpp -std=c++14 -Wall -Wextra -pedantic 
example.cpp:16:4: error: member reference type 'std::initializer_list<std::shared_ptr<Foo> >' is not a pointer; maybe you meant to use '.'? 
     p->Bar(); 
     ~^~ 
example.cpp:16:6: error: no member named 'Bar' in 'std::initializer_list<std::shared_ptr<Foo> >' 
     p->Bar(); 
     ~^
    2 errors generated. 

e

$ icpc -v 
icpc version 15.0.3 (gcc version 5.1.0 compatibility) 
$ icpc example.cpp -std=c++14 -Wall -Wextra -pedantic 
example.cpp(16): error: expression must have pointer type 
    p->Bar(); 
    ^
compilation aborted for example.cpp (code 2) 
+6

@ 0x499602D2: Non ha senso. Lo scopo di uno standard linguistico è definire in modo univoco la semantica del programma. –

+0

@LightnessRacesinOrbit: Mentre sono d'accordo, che non è il caso qui, la tua affermazione non è vera in generale: per uno, hai - specialmente in C e C++ - UB e IB, nel qual caso QUALSIASI comportamento è corretto (per IB deve solo essere documentato). Quindi hai un comportamento opzionale (ad esempio copia elision) e, infine, anche uno standard internazionale può contenere errori che potrebbero causare situazioni ambigue. – MikeMB

+1

@MikeMB: Sentitevi liberi di mostrarmi un esempio di quando IB porta all'errore del compilatore in un'implementazione ma non in un'altra. E UB non conta, per definizione. –

risposta

15

Tl; DR

Questo comportamento è oggetto di una proposta e di un problema del gruppo di lavoro sull'evoluzione. C'è qualche ambiguità sul fatto che questo sia considerato un difetto di C++ 14 o una proposta di C++ 1z. Se risulta essere un difetto di C++ 14, il comportamento di gcc è corretto per C++ 14. D'altra parte se questa è davvero una proposta C++ 1z allora clang e icpc stanno mostrando un comportamento corretto.

dettagli

Sembra che questo caso è coperto da N3681 che dice:

Auto e rinforzato inizializzatori causano un problema ricettività; vogliamo insegnare alle persone a utilizzare l'inizializzazione uniforme, ma dobbiamo dire allo in modo specifico ai programmatori di evitare le parentesi graffe con auto. In C++ 14, abbiamo ora più casi in cui auto e parentesi graffe sono problematici; il tipo di ritorno deduzione per funzioni evita parzialmente il problema, dal momento che restituire una lista rinforzata non funzionerà in quanto non è un'espressione. Tuttavia, restituendo una variabile automatica inizializzata da un inizializzatore rinforzato restituisce ancora un inizializzatore_list, invitando un comportamento non definito. Le acquisizioni di Lambda init hanno lo stesso problema. Questo documento propone di modificare un auto inizializzato con parentesi graffe per non dedursi a un elenco di inizializzazione e su divieto di inizializzazione automatica del brace per i casi in cui l'inizializzatore rinforzato ha più di un elemento.

e fornisce i seguenti esempi:

auto x = foo(); // copy-initialization 
auto x{foo}; // direct-initialization, initializes an initializer_list 
int x = foo(); // copy-initialization 
int x{foo}; // direct-initialization 

quindi penso clang è attualmente corretto, l'ultima versione di clang fornisce questo avvertimento:

avvertimento: l'inizializzazione dell'elenco diretto di una variabile con un tipo dedotto cambierà significato in una versione futura di Clang; inserire un '=' per evitare un cambiamento nel comportamento [-Wfuture-compat]

Da EWG issue 161 che N3922 è stato adottato per questo.

come note Pretorio la proposta raccomanda questo è un C++ 14 difetto:

Direzione da EWG è che noi consideriamo questo un difetto in C++ 14.

ma clang's C++1z implementation status notes come una proposta C++ 1z che non è implementata.

Quindi, se questo è un difetto di C++ 14, ciò renderebbe gcc corretto ma non è chiaro per me se questo è veramente un difetto o una proposta.

T.C. indica in un comment here che è seems like the clang developers destinato a back-port questo. Non è successo e non è chiaro il perché.

+3

Scoot Myers parla di questo [qui] (https://channel9.msdn.com/Events/CPP/C-PP-Con-2014/Type-Deduction-and-Why-You-Care) a circa 30 minuti in. – NathanOliver

+1

Ciò che è interessante è che N3922 chiama questo un difetto di C++ 14 (che è quello che pensavo anch'esso), ma clang [claims] (http://clang.llvm.org/cxx_status.html) è un C++ 1z cambiare (cercare N3922 in quella pagina). gcc-5.1 accetta anche l'esempio in modalità OP in C++ 11. – Praetorian

+0

@Preetorian buon punto, mi stavo chiedendo, ho modificato la mia risposta per menzionarlo. –

Problemi correlati