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?
clang-3.2 generuje oczekiwany wynik. Może to błąd gcc? –
To jest błąd GCC. Clang robi to poprawnie. – Xeo
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. –