pair
and tuple
are not correctly implemented for is_constructible
with no argsSection: 21.3.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.
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.
Add to 22.3.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> {};Add to 22.4.12 [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 eachT
,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.
Change 22.3.2 [pairs.pair] around p3 as indicated:
constexpr pair();-4- Effects: Value-initializes first and second. -?- Remarks: This constructor shall not participate in overload resolution unless
-3- Requires:is_default_constructible<first_type>::value
is true andis_default_constructible<second_type>::value
is true.is_default_constructible<first_type>::value
is true andis_default_constructible<second_type>::value
is true. [Note: This behaviour can be implemented by a constructor template with default template arguments — end note].
Change 22.4.4.2 [tuple.cnstr] around p4 as indicated:
constexpr tuple();-5- Effects: Value initializes each element. -?- Remarks: This constructor shall not participate in overload resolution unless
-4- Requires:is_default_constructible<Ti>::value
is true for all i.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].