2012-12-27 9 views
19

W other topic, @Dietmar dał tego rozwiązania:Kolejność oceny elementów w liście inicjalizacji

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

stwierdzając, że

Zastosowanie inicjalizacji nawiasów działa, ponieważ kolejność oceny Argumenty w liście inicjatora nawiasów klamrowych to kolejność, w jakiej występują. (Podkreślenie moje)

Właściwy tekst z C++ Standard (n3485) jest

W inicjatora liście z usztywnione-init-liście, initializer-klauzule, w tym te, które wynikają z rozszerzeń paczek (14.5.3) są oceniane w kolejności, w jakiej się pojawiają. Oznacza to, że każde obliczenie wartości i efekt uboczny związany z daną komendą inicjalizującą jest sekwencjonowany przed każdym obliczeniem wartości i skutkiem ubocznym związanym z dowolną klauzulą ​​inicjalizującą, która następuje po niej na rozdzielonej przecinkami liście listy inicjalizacyjnej. [Uwaga: ta kolejność oceny zachowuje się niezależnie od semantyki inicjalizacji; na przykład ma zastosowanie, gdy elementy listy inicjalizującej są interpretowane jako argumenty wywołania konstruktora, chociaż zwykle nie ma ograniczeń kolejności dla argumentów wywołania. -end uwaga]


Więc starałem się przetestować za pomocą następującego kodu:

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); 
} 

oczekiwany wynik:

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

Rzeczywista wyjściowa:

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

Czy zrobiłem coś złego w moim kodzie testowym? Zmieniłem kod na:

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 

Ten sam efekt jak poprzednio. Przetestowałem swój kod pod numerem MinGW (GCC) 4.7.0 i 4.7.2. Nawet ideone daje this output.

Czy to błąd w kompilatorze?

+0

clang-3.2 generuje oczekiwany wynik. Może to błąd gcc? –

+4

To jest błąd GCC. Clang robi to poprawnie. – Xeo

+4

Czego oczekujesz od nas? "Tak, to błąd z powodu cytatu, który dajesz". Czy nie zostało to dziś powiedziane dwa razy?Zarówno w pytaniu @Dietmar, jak iw pytaniu Dietmar, cytowano i przytaczano przykłady, które stwierdzają, że zamówienie jest odłożone na prawo. –

Odpowiedz

8

Odpowiadając na moje własne pytanie. Usunięcie pytania nie byłoby dobrym pomysłem, ponieważ ktoś może mieć to samo pytanie w przyszłości.

Tak. Jest to błąd w kompilatorze GCC.

zaczerpnięte z komentarzem @Johannes Schaub do danego pytania.

+2

Należy zauważyć, że Visual Studio 12 firmy Microsoft (2013) ma ten sam błąd, który właśnie zgłosiłem na https://connect.microsoft.com/ VisualStudio/feedbackdetail/view/976911/brak wstępnie przygotowanej listy-inicjatora-od lewej do prawej – Oberon

+0

Czy jest jakieś obejście dla MSVC? – Ram

+0

Zostanie to poprawione w aktualizacji 2 MSVC 2015 (https://blogs.msdn.microsoft.com/vcblog/2016/02/11/compiler-improvements-in-vs-2015-update-2/) –

Powiązane problemy