From: Jonathan Wakely Date: Thu, 6 Jun 2019 12:13:36 +0000 (+0100) Subject: Refactor SFINAE constraints on std::tuple constructors X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d355635e6b96d5d9e67a526b6dfd534cd9a9dd57;p=gcc.git Refactor SFINAE constraints on std::tuple constructors Replace the _TC class template with the better-named _TupleConstraints one, which provides a different set of member functions. The new members do not distinguish construction from lvalues and rvalues, but expects the caller to do that by providing different template arguments. Within the std::tuple primary template and std::tuple partial specialization the _TupleConstraints members are used via new alias templates like _ImplicitCtor and _ExplicitCtor which makes the constructor constraints less verbose and repetitive. For example, where we previously had: template::template _MoveConstructibleTuple<_UElements...>() && _TMC<_UElements...>::template _ImplicitlyMoveConvertibleTuple<_UElements...>() && (sizeof...(_Elements) >= 1), bool>::type=true> constexpr tuple(_UElements&&... __elements) We now have: template(), _ImplicitCtor<_Valid, _UElements...> = true> constexpr tuple(_UElements&&... __elements) There are two semantic changes as a result of the refactoring: - The allocator-extended default constructor is now constrained. - The rewritten constraints fix PR 90700. * include/std/tuple (_TC): Replace with _TupleConstraints. (_TupleConstraints): New helper for SFINAE constraints, with more expressive member functions to reduce duplication when used. (tuple::_TC2, tuple::_TMC, tuple::_TNTC): Remove. (tuple::_TCC): Replace dummy type parameter with bool non-type parameter that can be used to check the pack size. (tuple::_ImplicitDefaultCtor, tuple::_ExplicitDefaultCtor) (tuple::_ImplicitCtor, tuple::_ExplicitCtor): New alias templates for checking constraints in constructors. (tuple::__valid_args, tuple::_UseOtherCtor, tuple::__use_other_ctor): New SFINAE helpers. (tuple::tuple): Use new helpers to reduce repitition in constraints. (tuple::tuple(allocator_arg_t, const Alloc&)): Constrain. (tuple::_TCC, tuple::_ImplicitDefaultCtor) (tuple::_ExplicitDefaultCtor, tuple::_ImplicitCtor) (tuple::_ExplicitCtor): New alias templates for checking constraints in constructors. (tuple::__is_alloc_arg()): New SFINAE helpers. (tuple::tuple): Use new helpers to reduce repitition in constraints. (tuple::tuple(allocator_arg_t, const Alloc&)): Constrain. * testsuite/20_util/tuple/cons/90700.cc: New test. * testsuite/20_util/tuple/cons/allocators.cc: Add default constructor to meet new constraint on allocator-extended default constructor. From-SVN: r271998 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index a1cd084855f..18c83069887 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,30 @@ +2019-06-06 Jonathan Wakely + + * include/std/tuple (_TC): Replace with _TupleConstraints. + (_TupleConstraints): New helper for SFINAE constraints, with more + expressive member functions to reduce duplication when used. + (tuple::_TC2, tuple::_TMC, tuple::_TNTC): Remove. + (tuple::_TCC): Replace dummy type parameter with bool non-type + parameter that can be used to check the pack size. + (tuple::_ImplicitDefaultCtor, tuple::_ExplicitDefaultCtor) + (tuple::_ImplicitCtor, tuple::_ExplicitCtor): New alias templates for + checking constraints in constructors. + (tuple::__valid_args, tuple::_UseOtherCtor, tuple::__use_other_ctor): + New SFINAE helpers. + (tuple::tuple): Use new helpers to reduce repitition in constraints. + (tuple::tuple(allocator_arg_t, const Alloc&)): Constrain. + (tuple::_TCC, tuple::_ImplicitDefaultCtor) + (tuple::_ExplicitDefaultCtor, tuple::_ImplicitCtor) + (tuple::_ExplicitCtor): New alias templates for checking + constraints in constructors. + (tuple::__is_alloc_arg()): New SFINAE helpers. + (tuple::tuple): Use new helpers to reduce repitition in + constraints. + (tuple::tuple(allocator_arg_t, const Alloc&)): Constrain. + * testsuite/20_util/tuple/cons/90700.cc: New test. + * testsuite/20_util/tuple/cons/allocators.cc: Add default constructor + to meet new constraint on allocator-extended default constructor. + 2019-06-03 Jonathan Wakely * include/bits/stl_map.h (map): Disable static assert for C++98 mode. diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 64516b1dece..980dd6d6270 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -433,90 +433,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Concept utility functions, reused in conditionally-explicit // constructors. - template - struct _TC - { - template - static constexpr bool _ConstructibleTuple() - { - return __and_...>::value; - } - - template - static constexpr bool _ImplicitlyConvertibleTuple() - { - return __and_...>::value; - } - - template - static constexpr bool _MoveConstructibleTuple() - { - return __and_...>::value; - } - - template - static constexpr bool _ImplicitlyMoveConvertibleTuple() - { - return __and_...>::value; - } - - template - static constexpr bool _NonNestedTuple() - { - return __and_<__not_, - __remove_cvref_t<_SrcTuple>>>, - __not_>, - __not_> - >::value; - } - - template - static constexpr bool _NotSameTuple() - { - return __not_, - __remove_cvref_t<_UElements>...>>::value; - } - }; - - template - struct _TC - { - template - static constexpr bool _ConstructibleTuple() + template + struct _TupleConstraints { - return false; - } + // Constraint for a non-explicit constructor. + // True iff each Ti in _Types... can be constructed from Ui in _UTypes... + // and every Ui is implicitly convertible to Ti. + template + static constexpr bool __is_implicitly_constructible() + { + return __and_..., + is_convertible<_UTypes, _Types>... + >::value; + } - template - static constexpr bool _ImplicitlyConvertibleTuple() - { - return false; - } + // Constraint for a non-explicit constructor. + // True iff each Ti in _Types... can be constructed from Ui in _UTypes... + // but not every Ui is implicitly convertible to Ti. + template + static constexpr bool __is_explicitly_constructible() + { + return __and_..., + __not_<__and_...>> + >::value; + } - template - static constexpr bool _MoveConstructibleTuple() - { - return false; - } + static constexpr bool __is_implicitly_default_constructible() + { + return __and_... + >::value; + } - template - static constexpr bool _ImplicitlyMoveConvertibleTuple() - { - return false; - } + static constexpr bool __is_explicitly_default_constructible() + { + return __and_..., + __not_<__and_< + std::__is_implicitly_default_constructible<_Types>...> + >>::value; + } + }; - template - static constexpr bool _NonNestedTuple() + // Partial specialization used when a required precondition isn't met, + // e.g. when sizeof...(_Types) != sizeof...(_UTypes). + template + struct _TupleConstraints { - return true; - } + template + static constexpr bool __is_implicitly_constructible() + { return false; } - template - static constexpr bool _NotSameTuple() - { - return true; - } - }; + template + static constexpr bool __is_explicitly_constructible() + { return false; } + }; /// Primary class template, tuple template @@ -524,21 +493,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typedef _Tuple_impl<0, _Elements...> _Inherited; - // Used for constraining the default constructor so - // that it becomes dependent on the constraints. - template - struct _TC2 - { - static constexpr bool _DefaultConstructibleTuple() - { - return __and_...>::value; - } - static constexpr bool _ImplicitlyDefaultConstructibleTuple() - { - return __and_<__is_implicitly_default_constructible<_Elements>...> - ::value; - } - }; + template + using _TCC = _TupleConstraints<_Cond, _Elements...>; + + // Constraint for non-explicit default constructor + template + using _ImplicitDefaultCtor = __enable_if_t< + _TCC<_Dummy>::__is_implicitly_default_constructible(), + bool>; + + // Constraint for explicit default constructor + template + using _ExplicitDefaultCtor = __enable_if_t< + _TCC<_Dummy>::__is_explicitly_default_constructible(), + bool>; + + // Constraint for non-explicit constructors + template + using _ImplicitCtor = __enable_if_t< + _TCC<_Cond>::template __is_implicitly_constructible<_Args...>(), + bool>; + + // Constraint for non-explicit constructors + template + using _ExplicitCtor = __enable_if_t< + _TCC<_Cond>::template __is_explicitly_constructible<_Args...>(), + bool>; template static constexpr @@ -546,12 +526,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __assignable() { return __and_...>::value; } + // Condition for noexcept-specifier of an assignment operator. template static constexpr bool __nothrow_assignable() { return __and_...>::value; } + + // Condition for noexcept-specifier of a constructor. template static constexpr bool __nothrow_constructible() { @@ -559,205 +542,176 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __and_...>::value; } - public: - template:: - _ImplicitlyDefaultConstructibleTuple(), - bool>::type = true> - constexpr tuple() - noexcept(__and_...>::value) - : _Inherited() { } + // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) == 1. + template + static constexpr bool __valid_args() + { + return sizeof...(_Elements) == 1 + && !is_same>::value; + } - template:: - _DefaultConstructibleTuple() - && - !_TC2<_Dummy>:: - _ImplicitlyDefaultConstructibleTuple(), - bool>::type = false> - explicit constexpr tuple() - noexcept(__and_...>::value) - : _Inherited() { } - - // Shortcut for the cases where constructors taking _Elements... - // need to be constrained. - template using _TCC = - _TC::value, - _Elements...>; + // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) > 1. + template + static constexpr bool __valid_args() + { return (sizeof...(_Tail) + 2) == sizeof...(_Elements); } + + /* Constraint for constructors with a tuple parameter ensures + * that the constructor is only viable when it would not interfere with + * tuple(UTypes&&...) or tuple(const tuple&) or tuple(tuple&&). + * Such constructors are only viable if: + * either sizeof...(Types) != 1, + * or (when Types... expands to T and UTypes... expands to U) + * is_convertible_v, is_constructible_v, + * and is_same_v are all false. + */ + template> + struct _UseOtherCtor + : false_type + { }; + // If TUPLE is convertible to the single element in *this, + // then TUPLE should match tuple(UTypes&&...) instead. + template + struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Up>> + : __or_, is_constructible<_Tp, _Tuple>> + { }; + // If TUPLE and *this each have a single element of the same type, + // then TUPLE should match a copy/move constructor instead. + template + struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Tp>> + : true_type + { }; + + // Return true iff sizeof...(Types) == 1 && tuple_size_v == 1 + // and the single element in Types can be initialized from TUPLE, + // or is the same type as tuple_element_t<0, TUPLE>. + template + static constexpr bool __use_other_ctor() + { return _UseOtherCtor<_Tuple>::value; } + public: template::template - _ConstructibleTuple<_Elements...>() - && _TCC<_Dummy>::template - _ImplicitlyConvertibleTuple<_Elements...>() - && (sizeof...(_Elements) >= 1), - bool>::type=true> - constexpr tuple(const _Elements&... __elements) - noexcept(__nothrow_constructible()) - : _Inherited(__elements...) { } + _ImplicitDefaultCtor::value> = true> + constexpr + tuple() + noexcept(__and_...>::value) + : _Inherited() { } template::template - _ConstructibleTuple<_Elements...>() - && !_TCC<_Dummy>::template - _ImplicitlyConvertibleTuple<_Elements...>() - && (sizeof...(_Elements) >= 1), - bool>::type=false> - explicit constexpr tuple(const _Elements&... __elements) - noexcept(__nothrow_constructible()) - : _Inherited(__elements...) { } - - // Shortcut for the cases where constructors taking _UElements... - // need to be constrained. - template using _TMC = - _TC<(sizeof...(_Elements) == sizeof...(_UElements)) - && (_TC<(sizeof...(_UElements)==1), _Elements...>:: - template _NotSameTuple<_UElements...>()), - _Elements...>; - - // Shortcut for the cases where constructors taking tuple<_UElements...> - // need to be constrained. - template using _TMCT = - _TC<(sizeof...(_Elements) == sizeof...(_UElements)) - && !is_same, - tuple<_UElements...>>::value, - _Elements...>; - - template::template - _MoveConstructibleTuple<_UElements...>() - && _TMC<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>() - && (sizeof...(_Elements) >= 1), - bool>::type=true> - constexpr tuple(_UElements&&... __elements) - noexcept(__nothrow_constructible<_UElements...>()) - : _Inherited(std::forward<_UElements>(__elements)...) { } - - template::template - _MoveConstructibleTuple<_UElements...>() - && !_TMC<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>() - && (sizeof...(_Elements) >= 1), - bool>::type=false> - explicit constexpr tuple(_UElements&&... __elements) - noexcept(__nothrow_constructible<_UElements...>()) + _ExplicitDefaultCtor::value> = false> + explicit constexpr + tuple() + noexcept(__and_...>::value) + : _Inherited() { } + + template= 1), + _ImplicitCtor<_NotEmpty, const _Elements&...> = true> + constexpr + tuple(const _Elements&... __elements) + noexcept(__nothrow_constructible()) + : _Inherited(__elements...) { } + + template= 1), + _ExplicitCtor<_NotEmpty, const _Elements&...> = false> + explicit constexpr + tuple(const _Elements&... __elements) + noexcept(__nothrow_constructible()) + : _Inherited(__elements...) { } + + template(), + _ImplicitCtor<_Valid, _UElements...> = true> + constexpr + tuple(_UElements&&... __elements) + noexcept(__nothrow_constructible<_UElements...>()) + : _Inherited(std::forward<_UElements>(__elements)...) { } + + template(), + _ExplicitCtor<_Valid, _UElements...> = false> + explicit constexpr + tuple(_UElements&&... __elements) + noexcept(__nothrow_constructible<_UElements...>()) : _Inherited(std::forward<_UElements>(__elements)...) { } constexpr tuple(const tuple&) = default; constexpr tuple(tuple&&) = default; - // Shortcut for the cases where constructors taking tuples - // must avoid creating temporaries. - template using _TNTC = - _TC::value && sizeof...(_Elements) == 1, - _Elements...>; - - template::template - _ConstructibleTuple<_UElements...>() - && _TMCT<_UElements...>::template - _ImplicitlyConvertibleTuple<_UElements...>() - && _TNTC<_Dummy>::template - _NonNestedTuple&>(), - bool>::type=true> - constexpr tuple(const tuple<_UElements...>& __in) - noexcept(__nothrow_constructible()) - : _Inherited(static_cast&>(__in)) - { } - - template::template - _ConstructibleTuple<_UElements...>() - && !_TMCT<_UElements...>::template - _ImplicitlyConvertibleTuple<_UElements...>() - && _TNTC<_Dummy>::template - _NonNestedTuple&>(), - bool>::type=false> - explicit constexpr tuple(const tuple<_UElements...>& __in) - noexcept(__nothrow_constructible()) - : _Inherited(static_cast&>(__in)) - { } - - template::template - _MoveConstructibleTuple<_UElements...>() - && _TMCT<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>() - && _TNTC<_Dummy>::template - _NonNestedTuple&&>(), - bool>::type=true> - constexpr tuple(tuple<_UElements...>&& __in) - noexcept(__nothrow_constructible<_UElements...>()) - : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } - - template::template - _MoveConstructibleTuple<_UElements...>() - && !_TMCT<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>() - && _TNTC<_Dummy>::template - _NonNestedTuple&&>(), - bool>::type=false> - explicit constexpr tuple(tuple<_UElements...>&& __in) - noexcept(__nothrow_constructible<_UElements...>()) - : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } + template&>(), + _ImplicitCtor<_Valid, const _UElements&...> = true> + constexpr + tuple(const tuple<_UElements...>& __in) + noexcept(__nothrow_constructible()) + : _Inherited(static_cast&>(__in)) + { } + + template&>(), + _ExplicitCtor<_Valid, const _UElements&...> = false> + explicit constexpr + tuple(const tuple<_UElements...>& __in) + noexcept(__nothrow_constructible()) + : _Inherited(static_cast&>(__in)) + { } + + template&&>(), + _ImplicitCtor<_Valid, _UElements...> = true> + constexpr + tuple(tuple<_UElements...>&& __in) + noexcept(__nothrow_constructible<_UElements...>()) + : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } + + template&&>(), + _ExplicitCtor<_Valid, _UElements...> = false> + explicit constexpr + tuple(tuple<_UElements...>&& __in) + noexcept(__nothrow_constructible<_UElements...>()) + : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } // Allocator-extended constructors. - template + template::value> = true> tuple(allocator_arg_t __tag, const _Alloc& __a) : _Inherited(__tag, __a) { } - template::template - _ConstructibleTuple<_Elements...>() - && _TCC<_Dummy>::template - _ImplicitlyConvertibleTuple<_Elements...>(), - bool>::type=true> + template= 1), + _ImplicitCtor<_NotEmpty, const _Elements&...> = true> tuple(allocator_arg_t __tag, const _Alloc& __a, const _Elements&... __elements) : _Inherited(__tag, __a, __elements...) { } - template::template - _ConstructibleTuple<_Elements...>() - && !_TCC<_Dummy>::template - _ImplicitlyConvertibleTuple<_Elements...>(), - bool>::type=false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, - const _Elements&... __elements) + template= 1), + _ExplicitCtor<_NotEmpty, const _Elements&...> = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, + const _Elements&... __elements) : _Inherited(__tag, __a, __elements...) { } - template::template - _MoveConstructibleTuple<_UElements...>() - && _TMC<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>(), - bool>::type=true> + template(), + _ImplicitCtor<_Valid, _UElements...> = true> tuple(allocator_arg_t __tag, const _Alloc& __a, _UElements&&... __elements) : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) - { } - - template::template - _MoveConstructibleTuple<_UElements...>() - && !_TMC<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>(), - bool>::type=false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + { } + + template(), + _ExplicitCtor<_Valid, _UElements...> = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, _UElements&&... __elements) : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) - { } + { } template tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) @@ -767,61 +721,43 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } - template::template - _ConstructibleTuple<_UElements...>() - && _TMCT<_UElements...>::template - _ImplicitlyConvertibleTuple<_UElements...>() - && _TNTC<_Dummy>::template - _NonNestedTuple&&>(), - bool>::type=true> + template&>(), + _ImplicitCtor<_Valid, const _UElements&...> = true> tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple<_UElements...>& __in) : _Inherited(__tag, __a, static_cast&>(__in)) { } - template::template - _ConstructibleTuple<_UElements...>() - && !_TMCT<_UElements...>::template - _ImplicitlyConvertibleTuple<_UElements...>() - && _TNTC<_Dummy>::template - _NonNestedTuple&&>(), - bool>::type=false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + template&>(), + _ExplicitCtor<_Valid, const _UElements&...> = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple<_UElements...>& __in) : _Inherited(__tag, __a, static_cast&>(__in)) { } - template::template - _MoveConstructibleTuple<_UElements...>() - && _TMCT<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>() - && _TNTC<_Dummy>::template - _NonNestedTuple&&>(), - bool>::type=true> + template&&>(), + _ImplicitCtor<_Valid, _UElements...> = true> tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_UElements...>&& __in) : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } - template::template - _MoveConstructibleTuple<_UElements...>() - && !_TMCT<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>() - && _TNTC<_Dummy>::template - _NonNestedTuple&&>(), - bool>::type=false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + template&&>(), + _ExplicitCtor<_Valid, _UElements...> = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_UElements...>&& __in) : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) @@ -910,6 +846,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typedef _Tuple_impl<0, _T1, _T2> _Inherited; + // Constraint for non-explicit default constructor + template + using _ImplicitDefaultCtor = __enable_if_t< + _TupleConstraints<_Dummy, _U1, _U2>:: + __is_implicitly_default_constructible(), + bool>; + + // Constraint for explicit default constructor + template + using _ExplicitDefaultCtor = __enable_if_t< + _TupleConstraints<_Dummy, _U1, _U2>:: + __is_explicitly_default_constructible(), + bool>; + + template + using _TCC = _TupleConstraints<_Dummy, _T1, _T2>; + + // Constraint for non-explicit constructors + template + using _ImplicitCtor = __enable_if_t< + _TCC<_Cond>::template __is_implicitly_constructible<_U1, _U2>(), + bool>; + + // Constraint for non-explicit constructors + template + using _ExplicitCtor = __enable_if_t< + _TCC<_Cond>::template __is_explicitly_constructible<_U1, _U2>(), + bool>; + template static constexpr bool __assignable() { @@ -937,215 +902,146 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION is_nothrow_default_constructible<_T2>>::value; } + template + static constexpr bool __is_alloc_arg() + { return is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value; } + public: - template , - __is_implicitly_default_constructible<_U2>> - ::value, bool>::type = true> - constexpr tuple() + template = true> + constexpr + tuple() noexcept(__nothrow_default_constructible()) : _Inherited() { } - template , - is_default_constructible<_U2>, - __not_< - __and_<__is_implicitly_default_constructible<_U1>, - __is_implicitly_default_constructible<_U2>>>> - ::value, bool>::type = false> - explicit constexpr tuple() + template = false> + explicit constexpr + tuple() noexcept(__nothrow_default_constructible()) : _Inherited() { } - // Shortcut for the cases where constructors taking _T1, _T2 - // need to be constrained. - template using _TCC = - _TC::value, _T1, _T2>; - - template::template - _ConstructibleTuple<_T1, _T2>() - && _TCC<_Dummy>::template - _ImplicitlyConvertibleTuple<_T1, _T2>(), - bool>::type = true> - constexpr tuple(const _T1& __a1, const _T2& __a2) - noexcept(__nothrow_constructible()) - : _Inherited(__a1, __a2) { } - - template::template - _ConstructibleTuple<_T1, _T2>() - && !_TCC<_Dummy>::template - _ImplicitlyConvertibleTuple<_T1, _T2>(), - bool>::type = false> - explicit constexpr tuple(const _T1& __a1, const _T2& __a2) - noexcept(__nothrow_constructible()) - : _Inherited(__a1, __a2) { } - - // Shortcut for the cases where constructors taking _U1, _U2 - // need to be constrained. - using _TMC = _TC; - - template() - && _TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>() - && !is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value, - bool>::type = true> - constexpr tuple(_U1&& __a1, _U2&& __a2) - noexcept(__nothrow_constructible<_U1, _U2>()) + template = true> + constexpr + tuple(const _T1& __a1, const _T2& __a2) + noexcept(__nothrow_constructible()) + : _Inherited(__a1, __a2) { } + + template = false> + explicit constexpr + tuple(const _T1& __a1, const _T2& __a2) + noexcept(__nothrow_constructible()) + : _Inherited(__a1, __a2) { } + + template(), _U1, _U2> = true> + constexpr + tuple(_U1&& __a1, _U2&& __a2) + noexcept(__nothrow_constructible<_U1, _U2>()) : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } - template() - && !_TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>() - && !is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value, - bool>::type = false> - explicit constexpr tuple(_U1&& __a1, _U2&& __a2) - noexcept(__nothrow_constructible<_U1, _U2>()) + template(), _U1, _U2> = false> + explicit constexpr + tuple(_U1&& __a1, _U2&& __a2) + noexcept(__nothrow_constructible<_U1, _U2>()) : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } constexpr tuple(const tuple&) = default; constexpr tuple(tuple&&) = default; - template() - && _TMC::template - _ImplicitlyConvertibleTuple<_U1, _U2>(), - bool>::type = true> - constexpr tuple(const tuple<_U1, _U2>& __in) - noexcept(__nothrow_constructible()) + template = true> + constexpr + tuple(const tuple<_U1, _U2>& __in) + noexcept(__nothrow_constructible()) : _Inherited(static_cast&>(__in)) { } - template() - && !_TMC::template - _ImplicitlyConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit constexpr tuple(const tuple<_U1, _U2>& __in) - noexcept(__nothrow_constructible()) + template = false> + explicit constexpr + tuple(const tuple<_U1, _U2>& __in) + noexcept(__nothrow_constructible()) : _Inherited(static_cast&>(__in)) { } - template() - && _TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = true> - constexpr tuple(tuple<_U1, _U2>&& __in) - noexcept(__nothrow_constructible<_U1, _U2>()) + template = true> + constexpr + tuple(tuple<_U1, _U2>&& __in) + noexcept(__nothrow_constructible<_U1, _U2>()) : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } - template() - && !_TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit constexpr tuple(tuple<_U1, _U2>&& __in) - noexcept(__nothrow_constructible<_U1, _U2>()) + template = false> + explicit constexpr + tuple(tuple<_U1, _U2>&& __in) + noexcept(__nothrow_constructible<_U1, _U2>()) : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } - template() - && _TMC::template - _ImplicitlyConvertibleTuple<_U1, _U2>(), - bool>::type = true> - constexpr tuple(const pair<_U1, _U2>& __in) - noexcept(__nothrow_constructible()) + template = true> + constexpr + tuple(const pair<_U1, _U2>& __in) + noexcept(__nothrow_constructible()) : _Inherited(__in.first, __in.second) { } - template() - && !_TMC::template - _ImplicitlyConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit constexpr tuple(const pair<_U1, _U2>& __in) - noexcept(__nothrow_constructible()) + template = false> + explicit constexpr + tuple(const pair<_U1, _U2>& __in) + noexcept(__nothrow_constructible()) : _Inherited(__in.first, __in.second) { } - template() - && _TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = true> - constexpr tuple(pair<_U1, _U2>&& __in) - noexcept(__nothrow_constructible<_U1, _U2>()) + template = true> + constexpr + tuple(pair<_U1, _U2>&& __in) + noexcept(__nothrow_constructible<_U1, _U2>()) : _Inherited(std::forward<_U1>(__in.first), std::forward<_U2>(__in.second)) { } - template() - && !_TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit constexpr tuple(pair<_U1, _U2>&& __in) - noexcept(__nothrow_constructible<_U1, _U2>()) + template = false> + explicit constexpr + tuple(pair<_U1, _U2>&& __in) + noexcept(__nothrow_constructible<_U1, _U2>()) : _Inherited(std::forward<_U1>(__in.first), std::forward<_U2>(__in.second)) { } // Allocator-extended constructors. - template + template::value, _T1, _T2> = true> tuple(allocator_arg_t __tag, const _Alloc& __a) : _Inherited(__tag, __a) { } - template::template - _ConstructibleTuple<_T1, _T2>() - && _TCC<_Dummy>::template - _ImplicitlyConvertibleTuple<_T1, _T2>(), - bool>::type=true> + template = true> tuple(allocator_arg_t __tag, const _Alloc& __a, const _T1& __a1, const _T2& __a2) : _Inherited(__tag, __a, __a1, __a2) { } - template::template - _ConstructibleTuple<_T1, _T2>() - && !_TCC<_Dummy>::template - _ImplicitlyConvertibleTuple<_T1, _T2>(), - bool>::type=false> - - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + template = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, const _T1& __a1, const _T2& __a2) : _Inherited(__tag, __a, __a1, __a2) { } - template() - && _TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = true> + template = true> tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2) : _Inherited(__tag, __a, std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } - template() - && !_TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, - _U1&& __a1, _U2&& __a2) + template = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, + _U1&& __a1, _U2&& __a2) : _Inherited(__tag, __a, std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } @@ -1157,89 +1053,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } - template() - && _TMC::template - _ImplicitlyConvertibleTuple<_U1, _U2>(), - bool>::type = true> + template = true> tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple<_U1, _U2>& __in) : _Inherited(__tag, __a, static_cast&>(__in)) { } - template() - && !_TMC::template - _ImplicitlyConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + template = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple<_U1, _U2>& __in) : _Inherited(__tag, __a, static_cast&>(__in)) { } - template() - && _TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = true> + template = true> tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } - template() - && !_TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, - tuple<_U1, _U2>&& __in) + template = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } - template() - && _TMC::template - _ImplicitlyConvertibleTuple<_U1, _U2>(), - bool>::type = true> - tuple(allocator_arg_t __tag, const _Alloc& __a, + template = true> + tuple(allocator_arg_t __tag, const _Alloc& __a, const pair<_U1, _U2>& __in) : _Inherited(__tag, __a, __in.first, __in.second) { } - template() - && !_TMC::template - _ImplicitlyConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + template = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, const pair<_U1, _U2>& __in) : _Inherited(__tag, __a, __in.first, __in.second) { } - template() - && _TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = true> - tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) + template = true> + tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) : _Inherited(__tag, __a, std::forward<_U1>(__in.first), std::forward<_U2>(__in.second)) { } - template() - && !_TMC::template - _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), - bool>::type = false> - explicit tuple(allocator_arg_t __tag, const _Alloc& __a, - pair<_U1, _U2>&& __in) + template = false> + explicit + tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) : _Inherited(__tag, __a, std::forward<_U1>(__in.first), std::forward<_U2>(__in.second)) { } diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/90700.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/90700.cc new file mode 100644 index 00000000000..08e7787bf4f --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/90700.cc @@ -0,0 +1,66 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do compile { target c++11 } } + +#include +#include + +struct X { }; + +struct Y +{ + Y(const std::tuple&) = delete; + Y(std::tuple&&) { throw 1; } + Y(const X&) { } +}; + +struct Z +{ + Z(X&&) { } + Z(const std::tuple&) { throw 1; } + Z(std::tuple&&) = delete; +}; + +void +test01() +{ + // PR libstdc++/90700 wrong constraints on constructor + const std::allocator a; + const std::tuple x; + + static_assert(!std::is_convertible&, Y>::value, ""); + static_assert(!std::is_constructible&>::value, ""); + static_assert(!std::is_same::value, ""); + // should use tuple::tuple(allocator_arg_t, const A&, const tuple&) + // and construct Y from X: + std::tuple y(std::allocator_arg, a, x); +} + +void +test02() +{ + const std::allocator a; + std::tuple x; + + static_assert(!std::is_convertible, Z>::value, ""); + static_assert(!std::is_constructible>::value, ""); + static_assert(!std::is_same::value, ""); + // should use tuple::tuple(allocator_arg_t, const A&, tuple&&) + // and construct Z from X: + std::tuple z(std::allocator_arg, a, std::move(x)); +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/allocators.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/allocators.cc index 92938ecb450..c804bb884e9 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/cons/allocators.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/allocators.cc @@ -186,12 +186,26 @@ void test03() struct dr2586 { using allocator_type = std::allocator; + dr2586() { } dr2586(std::allocator_arg_t, allocator_type&&) { } - dr2586(const allocator_type&) { } + dr2586(const allocator_type&) : expected(true) { } + bool expected = false; }; const dr2586::allocator_type a; std::tuple t{std::allocator_arg, a}; + VERIFY( std::get<0>(t).expected ); +} + +void test04() +{ + struct X { + X(std::allocator_arg_t) { } + }; + + // The element types are not default constructible, so the allocator-extended + // default constructor should not participate in overload resolution. + std::tuple t(std::allocator_arg, *+[]{}); } int main() @@ -199,5 +213,6 @@ int main() test01(); test02(); test03(); + test04(); return 0; }