2528. Order of std::tuple construction unspecified

Section: 23.5.3.1 [tuple.cnstr] Status: New Submitter: Brian Rodriguez Opened: 2015-08-25 Last modified: 2017-02-19

Priority: 3

View other active issues in [tuple.cnstr].

View all other issues in [tuple.cnstr].

View all issues with New status.

Discussion:

The std::tuple order of element construction is unspecified. It is either in the same order of the type list or in reverse.

Consider the following program:

#include <iostream>
#include <tuple>

struct X 
{
  X(int) { std::cout << "X constructor\n"; }
};

struct Y 
{
  Y(int) { std::cout << "Y constructor\n"; }
};

int main()
{
  std::tuple<X, Y> t(1, 2);
}

Here is a link to two sample compilations. The first uses libstdc++ and constructs in reverse order, and the second uses libc++ and constructs in in-order.

A std::tuple mimics both a struct and type-generic container and should thus follow their standards. Construction is fundamentally different from a function call, and it has been historically important for a specific order to be guaranteed; namely: whichever the developer may decide. Mandating construction order will allow developers to reference younger elements later on in the chain as well, much like a struct allows you to do with its members.

There are implementation issues as well. Reversed lists will require unnecessary overhead for braced-initializer-list initialization. Since lists are evaluated from left to right, the initializers must be placed onto the stack to respect the construction order. This issue could be significant for large tuples, deeply nested tuples, or tuples with elements that require many constructor arguments.

I propose that the std::tuple<A, B, ..., Y, Z>'s constructor implementation be standardized, and made to construct in the same order as its type list e.g. A{}, B{}, ..., Y{}, Z{}.

Daniel:

When N3140 became accepted, wording had been added that gives at least an indication of requiring element initialization in the order of the declaration of the template parameters. This argumentation can be based on 23.5.3.1 [tuple.cnstr] p3 (emphasize mine):

-3- In the constructor descriptions that follow, let i be in the range [0,sizeof...(Types)) in order, Ti be the ith type in Types, and Ui be the ith type in a template parameter pack named UTypes, where indexing is zero-based.

But the current wording needs to be improved to make that intention clearer and an issue like this one is necessary to be sure that the committee is agreeing (or disagreeing) with that intention, especially because N3140 didn't really point out the relevance of the element construction order in the discussion, and because not all constructors explicitly refer to the ordered sequence of numbers generated by the variable i (The move constructor does it right, but most other don't do that).

[2017-02-12, Alisdair comments]

Note that this issue should not be extended to cover the assignment operators, as implementations may want the freedom to re-order member-wise assignment so that, for example, all potentially-throwing assignments are performed before non-throwing assignments (as indicated by the noexcept operator).

Proposed resolution: