The following program:
#include
#include
struct A {
A() { std::cout << \"A constructor\\n\"; }
};
struct B {
B
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.
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);