2012-12-27 6 views
19

Nel other topic, @Dietmar ha dato questa soluzione:ordine di valutazione degli elementi nella lista-inizializzazione

template <typename... T> 
std::tuple<T...> parse(std::istream& in) 
{ 
    return std::tuple<T...>{ T(in)... }; 
} 

affermando che,

L'uso di inizializzazione del tutore funziona perché il ordine di valutazione degli argomenti in un elenco di inizializzazione delle parentesi graffe è l'ordine in cui appaiono. (Sottolineare la mia)

Il testo pertinente dal ++ standard C (n3485) è,

All'interno di inizializzazione-list di a-init-list rinforzato, l'inizializzatore-clausole, comprese quelle che risultano dalle espansioni del pacchetto (14.5.3), vengono valutate nell'ordine in cui appaiono. Cioè, ogni calcolo del valore ed effetto collaterale associato ad una data clausola di inizializzazione viene sequenziato prima di ogni calcolo del valore ed effetto collaterale associato a qualsiasi clausola inizializzatore che la segue nell'elenco separato da virgole della lista inizializzatore. [Nota: questo ordine di valutazione è valido indipendentemente dalla semantica dell'inizializzazione; ad esempio, si applica quando gli elementi dell'elenco inizializzatore vengono interpretati come argomenti di una chiamata del costruttore, anche se normalmente non vi sono vincoli di sequenziamento sugli argomenti di una chiamata. -end nota]


così ho provato a testare questo con il seguente codice:

template<int N> 
struct A 
{ 
    std::string data; 
    A(std::istream & stream) { stream >> data; } 
    friend std::ostream& operator<<(std::ostream & out, A<N> const & a) 
    { 
     return out << "A"<<N<<"::data = " << a.data; 
    } 
}; 
typedef A<1> A1; 
typedef A<2> A2; 

template<typename ...Args> 
void test(std::istream & stream) 
{ 
    std::tuple<Args...> args { Args(stream)... }; 
    std::cout << std::get<0>(args) << std::endl; 
    std::cout << std::get<1>(args) << std::endl; 
} 

int main() 
{ 
    std::stringstream ss("A1 A2"); 
    test<A1,A2>(ss); 
} 

uscita prevista:

A1::data = A1 
A2::data = A2 

uscita effettiva:

A1::data = A2 
A2::data = A1 

Ho fatto qualcosa di sbagliato nel mio codice di test? Ho cambiato il mio codice a questo:

std::stringstream ss("A1 A2"); 
std::tuple<A1,A2> args{A1(ss), A2(ss)}; 
std::cout << std::get<0>(args) << std::endl; 
std::cout << std::get<1>(args) << std::endl 

Stesso risultato di prima. Ho testato il mio codice con MinGW (GCC) 4.7.0 e 4.7.2. Anche ideone dà this output.

È un errore nel compilatore?

+0

clang-3.2 genera l'output previsto. Forse è un bug gcc? –

+4

Questo è un bug GCC. Clang lo fa corretto. – Xeo

+4

Cosa ci aspetti da noi? "Sì, è un bug a causa della citazione che stai dando". Non è stato detto due volte oggi?Sia nella domanda di @Dietmar che nella domanda i riferimenti di Dietmar sono stati forniti citazioni ed esempi che affermano che l'ordine è da sinistra a destra. –

risposta

8

Rispondere alla mia domanda. Eliminare la domanda non sarebbe una buona idea, in quanto qualcuno potrebbe avere la stessa domanda in futuro.

Sì. È un bug nel compilatore GCC.

tratto dal commento di @Johannes Schaub alla domanda.

+2

Nota che Microsoft Visual Studio 12 (2013) presenta lo stesso bug, che ho appena segnalato all'indirizzo https://connect.microsoft.com/ VisualStudio/feedbackdetail/view/976911/braced-inizializzatore-elenco-non valutato-left-to-right – Oberon

+0

Esiste un problema con MSVC? – Ram

+0

Questo problema verrà risolto nell'aggiornamento 2 di MSVC 2015 (https://blogs.msdn.microsoft.com/vcblog/2016/02/11/compiler-improvements-in-vs-2015-update-2/) –