Reputation: 4376
The following program:
#include <iostream>
#include <tuple>
struct A {
A() { std::cout << "A constructor\n"; }
};
struct B {
B() { std::cout << "B constructor\n"; }
};
int main() {
std::tuple<A, B> t;
}
gives different outputs on different compilers:
# libstdc++
B constructor
A constructor
# libc++
A constructor
B constructor
This seem weird... I figured the standard would have guaranteed the tuple elements be constructed in-order, e.g., A, B, ..., Y, Z?
Upvotes: 7
Views: 510
Reputation: 4376
std::tuple
construction order is currently unspecified.
A proposal for a concrete decision on its order has been submitted to the committee but until then the order should not be relied on.
Upvotes: 6
Reputation: 9725
As you've seen, the standard does not define an ordering here. I've only seen it happen in reverse order, but in principle a compiler could do anything it wanted. Worse, your request for a "standardized constructor" will not prosper, because this issue isn't specific to constructors: all function arguments work this way!
Consider this example:
bool putOnTheSpaceSuits() { /* ... */ }
bool openTheAirlock() { /* ... */ }
void tryGoIntoSpace(bool spaceSuitsOn, bool airlockOpen) {
if(spaceSuitsOn && airlockOpen) {
spacewalk();
}
}
What happens when we run tryGoIntoSpace(putOnTheSpaceSuits(), openTheAirlock())
? On my machine, openTheAirlock()
is evaluated first, dumping our unprotected astronauts into space. Oops!
Your original question uses two implicit conversions; it's equivalent to std::tuple<X,Y> t(X(1),Y(2));
. You can see the same effect with any random free function that takes an X
and a Y
:
void frob(X x, Y y) { /* ... */ }
frob(X(1), Y(2)); // It's unspecified, but I bet Y(2) will happen first here.
See for yourself: http://coliru.stacked-crooked.com/a/e4142f3c8342ebf2
The fact that you're using a recursively-templated tuple constructor isn't relevant here; all C++ functions are alike. Ideally your function arguments should not have interesting, mutually-interacting side effects, but if that's impossible, you have to do the ordering yourself:
X x(1);
Y y(2);
std::tuple<X,Y> t(x, y);
Upvotes: 2