This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++20 status.

3158. tuple(allocator_arg_t, const Alloc&) should be conditionally explicit

Section: 22.4.4.2 [tuple.cnstr] Status: C++20 Submitter: Jonathan Wakely Opened: 2018-08-21 Last modified: 2021-02-25

Priority: 3

View other active issues in [tuple.cnstr].

View all other issues in [tuple.cnstr].

View all issues with C++20 status.

Discussion:

std::tuple's allocator-extended constructors say "Effects: Equivalent to the preceding constructors except that each element is constructed with uses-allocator construction". That's not true for the first one, as shown by:

#include <tuple>

struct X { explicit X() { } };

std::tuple<X> f() { return {}; }
std::tuple<X> g() { return { std::allocator_arg, std::allocator<int>{} }; }

The function f() doesn't compile because of the explicit constructor, but g() does, despite using the same constructor for X. The conditional explicit-ness is not equivalent.

Also, the editor requested that we change "implicitly default-constructible" to use words that mean something. He suggested "copy-list-initializable from an empty list".

[2018-09 Reflector prioritization]

Set Priority to 3

[2019-02; Kona Wednesday night issue processing]

Status to Ready

Proposed resolution:

This wording is relative to N4762.

  1. Modify 22.4.4 [tuple.tuple], class template tuple synopsis, as indicated:

    […]
    // allocator-extended constructors
    template<class Alloc>
      explicit(see below) tuple(allocator_arg_t, const Alloc& a);
    template<class Alloc>
      explicit(see below) tuple(allocator_arg_t, const Alloc& a, const Types&...);
    […]
    
  2. Modify 22.4.4.2 [tuple.cnstr], as indicated:

    explicit(see below) constexpr tuple();
    

    -5- Effects: Value-initializes each element.

    -6- Remarks: This constructor shall not participate in overload resolution unless is_default_constructible_v<Ti> is true for all i. [Note: This behavior can be implemented by a constructor template with default template arguments. — end note] The expression inside explicit evaluates to true if and only if Ti is not implicitly default-constructible copy-list-initializable from an empty list for at least one i. [Note: This behavior can be implemented with a trait that checks whether a const Ti& can be initialized with {}. — end note]

    […]

    template<class Alloc>
      explicit(see below) tuple(allocator_arg_t, const Alloc& a);
    template<class Alloc>
      explicit(see below) tuple(allocator_arg_t, const Alloc& a, const Types&...);
    […]
    template<class Alloc, class U1, class U2>
      explicit(see below) tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);
    

    -25- Requires: Alloc shall satisfy the Cpp17Allocator requirements (Table 33).

    […]