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

### 2367. `pair` and `tuple` are not correctly implemented for `is_constructible` with no args

Section: 20.15.5.4 [meta.unary.prop] Status: C++17 Submitter: Howard Hinnant Opened: 2014-02-19 Last modified: 2017-07-30

Priority: 3

View other active issues in [meta.unary.prop].

View all other issues in [meta.unary.prop].

View all issues with C++17 status.

Discussion:

Consider:

>     struct X
>     {
>       X() = delete;
>     };

>     int main()
>     {
>       typedef std::pair<int, X> P;
>       static_assert(!std::is_constructible<P>::value, "");
>       static_assert(!std::is_default_constructible<P>::value, "");
>       typedef std::tuple<int, X> T;
>       static_assert(!std::is_constructible<T>::value, "");
>       static_assert(!std::is_default_constructible<T>::value, "");
>     }

For me these `static_asserts` fail. And worse than that, even asking the question fails (as opposed to gets the wrong answer):

>     assert(!std::is_constructible<P>::value);

In file included from test.cpp:2:

>     error:
>           call to deleted constructor of 'X'
>        pair() : first(), second() {}
>                          ^
>     note: function has been explicitly marked deleted here
>         X() = delete;
>         ^
>     1 error generated.

This can be solved by specializing `is_constructible` on `pair` and `tuple` for zero Args:

>     template <class T, class U>
>     struct is_constructible<pair<T, U>>
>       : integral_constant<bool, is_default_constructible<T>::value &&
>                                 is_default_constructible<U>::value>
>     {};

>     template <class ...T>
>     struct is_constructible<tuple<T...>>
>       : integral_constant<bool,
>                           __all<is_default_constructible<T>::value...>::value>
>     {};

Now everything just works.

[2014-05-14, Daniel comments]

The proposed resolution is incomplete, because it wouldn't work for cv-qualified objects of `pair` or for references of them during reference-initialization.

I would like to point out that the approach suggested in N3739 can be easily extended to solve the problem without need to muddle with specializing `is_constructible`:

>     template<class U1 = T1, class U2 = T2,
>       typename enable_if<
>         is_default_constructible<U1>::value && is_default_constructible<U2>::value
>       , bool>::type = false
>     >
>     constexpr pair();

The new wording proposal represents an alternative wording change that I would strongly prefer.

Previous resolution from Howard [SUPERSEDED]:

> This wording is relative to N3936.

> 1. Add to 20.4.3 [pairs.spec]:

>    >     template <class T, class U>
>    >     struct is_constructible<pair<T, U>>
>    >       : integral_constant<bool, is_default_constructible<T>::value &&
>    >                                 is_default_constructible<U>::value>
>    >     {};

> 2. Add to 20.5.10 [tuple.special]:

>    >     template <class ...T>
>    >     struct is_constructible<tuple<T...>>
>    >       : integral_constant<bool, see below>
>    >     {};

>    > > -?- The second argument to `integral_constant` shall be true if for each `T`, `is_default_constructible<T>::value` is true.

[2015-05, Lenexa]

STL: I object to this resolution due to British spelling of behavior
JW: we already have other places of this spelling
VV: the easy resolution is to remove the notes
MC: if that's all we want to change: put it in and make the editorial change of removing the note
VV: the other paper doesn't make any of these changes so it would be consistent
JW: this make me want even more the features of having constructors doing the Right Thing - I haven't written up the request to do something like that
VV: so it would be an aggregate reflecting the properties of the constituting types
JW: I should write that up
MC: any objection to move to ready? in favor: 16, opposed: 0, abstain: 1

Proposed resolution:

This wording is relative to N3936.

1. Change 20.4.2 [pairs.pair] around p3 as indicated:

   >     constexpr pair();

   > > -3- Requires: `is_default_constructible<first_type>::value` is true and `is_default_constructible<second_type>::value` is true.

   > > -4- Effects: Value-initializes first and second.

   > > -?- Remarks: This constructor shall not participate in overload resolution unless `is_default_constructible<first_type>::value` is true and `is_default_constructible<second_type>::value` is true. [Note: This behaviour can be implemented by a constructor template with default template arguments — end note].

2. Change 20.5.3.1 [tuple.cnstr] around p4 as indicated:

   >     constexpr tuple();

   > > -4- Requires: `is_default_constructible<Ti>::value` is true for all i.

   > > -5- Effects: Value initializes each element.

   > > -?- Remarks: This constructor shall not participate in overload resolution unless `is_default_constructible<Ti>::value` is true for all i. [Note: This behaviour can be implemented by a constructor template with default template arguments — end note].