Title
pair and tuple are not correctly implemented for is_constructible with no args
Status
c++17
Section
[meta.unary.prop]
Submitter
Howard Hinnant

Created on 2014-02-19.00:00:00 last changed 81 months ago

Messages

Date: 2015-05-07.23:01:40

Proposed resolution:

This wording is relative to N3936.

  1. Change [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 [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].

Date: 2015-05-07.23:01:40

[ 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

Date: 2014-05-15.00:00:00

[ 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 [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 [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.

Date: 2014-02-19.00:00:00

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.

History
Date User Action Args
2017-07-30 20:15:43adminsetstatus: wp -> c++17
2015-10-27 16:52:45adminsetstatus: ready -> wp
2015-05-07 23:01:40adminsetmessages: + msg7386
2015-05-07 23:01:40adminsetstatus: new -> ready
2014-05-14 21:21:48adminsetmessages: + msg6944
2014-03-24 21:23:12adminsetmessages: + msg6908
2014-02-19 00:00:00admincreate