Date
2018-08-18.17:38:43
Message id
10075

Content

For a 2-element std::tuple, attempting to call the "allocator-extended default constructor" might actually pass the allocator_arg tag and the allocator to the tuple element constructors:

tuple<any, any> t{allocator_arg, allocator<int>{}};
assert(std::get<0>(t).has_value());

This assertion should pass according to the standard, but users might expect the elements to be default constructed. If you really wanted to construct the elements with the tag and the allocator, you could do:

tuple<any, any> t{{allocator_arg}, {allocator<int>{}}};

or

tuple<any, any> t{tuple<allocator_arg_t, allocator<int>>{allocator_arg, allocator<int>{}}};

The deduction guides for std::tuple always treat {allocator_arg_t, an_allocator} as the allocator-extended default constructor, so this creates an empty tuple:

tuple t{allocator_arg, allocator<int>{}};

And this is needed to create tuple<any, any>:

tuple t{allocator_arg, allocator<int>{}, any{}, any{}};

The proposed resolution seems consistent with that, always calling an allocator-extended constructor for {allocator_arg_t, a}, instead of the tuple(UTypes&&...) constructor.

Ville Voutilainen:

This was discussed in this reflector thread, where Andrzej convinced me to change libstdc++ tuple.