Commit d355635e by Jonathan Wakely Committed by Jonathan Wakely

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<T1, T2> 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<typename... _UElements, typename
             enable_if<
                _TMC<_UElements...>::template
                   _MoveConstructibleTuple<_UElements...>()
                 && _TMC<_UElements...>::template
                   _ImplicitlyMoveConvertibleTuple<_UElements...>()
                 && (sizeof...(_Elements) >= 1),
       bool>::type=true>
       constexpr tuple(_UElements&&... __elements)

We now have:

     template<typename... _UElements,
             bool _Valid = __valid_args<_UElements...>(),
             _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<T1, T2>::_TCC, tuple<T1, T2>::_ImplicitDefaultCtor)
	(tuple<T1, T2>::_ExplicitDefaultCtor, tuple<T1, T2>::_ImplicitCtor)
	(tuple<T1, T2>::_ExplicitCtor): New alias templates for checking
	constraints in constructors.
	(tuple::__is_alloc_arg()): New SFINAE helpers.
	(tuple<T1, T2>::tuple): Use new helpers to reduce repitition in
	constraints.
	(tuple<T1, T2>::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
parent ec573765
2019-06-06 Jonathan Wakely <jwakely@redhat.com>
* 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<T1, T2>::_TCC, tuple<T1, T2>::_ImplicitDefaultCtor)
(tuple<T1, T2>::_ExplicitDefaultCtor, tuple<T1, T2>::_ImplicitCtor)
(tuple<T1, T2>::_ExplicitCtor): New alias templates for checking
constraints in constructors.
(tuple::__is_alloc_arg()): New SFINAE helpers.
(tuple<T1, T2>::tuple): Use new helpers to reduce repitition in
constraints.
(tuple<T1, T2>::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 <jwakely@redhat.com> 2019-06-03 Jonathan Wakely <jwakely@redhat.com>
* include/bits/stl_map.h (map): Disable static assert for C++98 mode. * include/bits/stl_map.h (map): Disable static assert for C++98 mode.
......
...@@ -433,90 +433,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -433,90 +433,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Concept utility functions, reused in conditionally-explicit // Concept utility functions, reused in conditionally-explicit
// constructors. // constructors.
template<bool, typename... _Elements> template<bool, typename... _Types>
struct _TC struct _TupleConstraints
{
template<typename... _UElements>
static constexpr bool _ConstructibleTuple()
{
return __and_<is_constructible<_Elements, const _UElements&>...>::value;
}
template<typename... _UElements>
static constexpr bool _ImplicitlyConvertibleTuple()
{
return __and_<is_convertible<const _UElements&, _Elements>...>::value;
}
template<typename... _UElements>
static constexpr bool _MoveConstructibleTuple()
{
return __and_<is_constructible<_Elements, _UElements&&>...>::value;
}
template<typename... _UElements>
static constexpr bool _ImplicitlyMoveConvertibleTuple()
{
return __and_<is_convertible<_UElements&&, _Elements>...>::value;
}
template<typename _SrcTuple>
static constexpr bool _NonNestedTuple()
{
return __and_<__not_<is_same<tuple<_Elements...>,
__remove_cvref_t<_SrcTuple>>>,
__not_<is_convertible<_SrcTuple, _Elements...>>,
__not_<is_constructible<_Elements..., _SrcTuple>>
>::value;
}
template<typename... _UElements>
static constexpr bool _NotSameTuple()
{
return __not_<is_same<tuple<_Elements...>,
__remove_cvref_t<_UElements>...>>::value;
}
};
template<typename... _Elements>
struct _TC<false, _Elements...>
{
template<typename... _UElements>
static constexpr bool _ConstructibleTuple()
{ {
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<typename... _UTypes>
static constexpr bool __is_implicitly_constructible()
{
return __and_<is_constructible<_Types, _UTypes>...,
is_convertible<_UTypes, _Types>...
>::value;
}
template<typename... _UElements> // Constraint for a non-explicit constructor.
static constexpr bool _ImplicitlyConvertibleTuple() // True iff each Ti in _Types... can be constructed from Ui in _UTypes...
{ // but not every Ui is implicitly convertible to Ti.
return false; template<typename... _UTypes>
} static constexpr bool __is_explicitly_constructible()
{
return __and_<is_constructible<_Types, _UTypes>...,
__not_<__and_<is_convertible<_UTypes, _Types>...>>
>::value;
}
template<typename... _UElements> static constexpr bool __is_implicitly_default_constructible()
static constexpr bool _MoveConstructibleTuple() {
{ return __and_<std::__is_implicitly_default_constructible<_Types>...
return false; >::value;
} }
template<typename... _UElements> static constexpr bool __is_explicitly_default_constructible()
static constexpr bool _ImplicitlyMoveConvertibleTuple() {
{ return __and_<is_default_constructible<_Types>...,
return false; __not_<__and_<
} std::__is_implicitly_default_constructible<_Types>...>
>>::value;
}
};
template<typename... _UElements> // Partial specialization used when a required precondition isn't met,
static constexpr bool _NonNestedTuple() // e.g. when sizeof...(_Types) != sizeof...(_UTypes).
template<typename... _Types>
struct _TupleConstraints<false, _Types...>
{ {
return true; template<typename... _UTypes>
} static constexpr bool __is_implicitly_constructible()
{ return false; }
template<typename... _UElements> template<typename... _UTypes>
static constexpr bool _NotSameTuple() static constexpr bool __is_explicitly_constructible()
{ { return false; }
return true; };
}
};
/// Primary class template, tuple /// Primary class template, tuple
template<typename... _Elements> template<typename... _Elements>
...@@ -524,21 +493,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -524,21 +493,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ {
typedef _Tuple_impl<0, _Elements...> _Inherited; typedef _Tuple_impl<0, _Elements...> _Inherited;
// Used for constraining the default constructor so template<bool _Cond>
// that it becomes dependent on the constraints. using _TCC = _TupleConstraints<_Cond, _Elements...>;
template<typename _Dummy>
struct _TC2 // Constraint for non-explicit default constructor
{ template<bool _Dummy>
static constexpr bool _DefaultConstructibleTuple() using _ImplicitDefaultCtor = __enable_if_t<
{ _TCC<_Dummy>::__is_implicitly_default_constructible(),
return __and_<is_default_constructible<_Elements>...>::value; bool>;
}
static constexpr bool _ImplicitlyDefaultConstructibleTuple() // Constraint for explicit default constructor
{ template<bool _Dummy>
return __and_<__is_implicitly_default_constructible<_Elements>...> using _ExplicitDefaultCtor = __enable_if_t<
::value; _TCC<_Dummy>::__is_explicitly_default_constructible(),
} bool>;
};
// Constraint for non-explicit constructors
template<bool _Cond, typename... _Args>
using _ImplicitCtor = __enable_if_t<
_TCC<_Cond>::template __is_implicitly_constructible<_Args...>(),
bool>;
// Constraint for non-explicit constructors
template<bool _Cond, typename... _Args>
using _ExplicitCtor = __enable_if_t<
_TCC<_Cond>::template __is_explicitly_constructible<_Args...>(),
bool>;
template<typename... _UElements> template<typename... _UElements>
static constexpr static constexpr
...@@ -546,12 +526,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -546,12 +526,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__assignable() __assignable()
{ return __and_<is_assignable<_Elements&, _UElements>...>::value; } { return __and_<is_assignable<_Elements&, _UElements>...>::value; }
// Condition for noexcept-specifier of an assignment operator.
template<typename... _UElements> template<typename... _UElements>
static constexpr bool __nothrow_assignable() static constexpr bool __nothrow_assignable()
{ {
return return
__and_<is_nothrow_assignable<_Elements&, _UElements>...>::value; __and_<is_nothrow_assignable<_Elements&, _UElements>...>::value;
} }
// Condition for noexcept-specifier of a constructor.
template<typename... _UElements> template<typename... _UElements>
static constexpr bool __nothrow_constructible() static constexpr bool __nothrow_constructible()
{ {
...@@ -559,205 +542,176 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -559,205 +542,176 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__and_<is_nothrow_constructible<_Elements, _UElements>...>::value; __and_<is_nothrow_constructible<_Elements, _UElements>...>::value;
} }
public: // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) == 1.
template<typename _Dummy = void, template<typename _Up>
typename enable_if<_TC2<_Dummy>:: static constexpr bool __valid_args()
_ImplicitlyDefaultConstructibleTuple(), {
bool>::type = true> return sizeof...(_Elements) == 1
constexpr tuple() && !is_same<tuple, __remove_cvref_t<_Up>>::value;
noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value) }
: _Inherited() { }
template<typename _Dummy = void, // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) > 1.
typename enable_if<_TC2<_Dummy>:: template<typename, typename, typename... _Tail>
_DefaultConstructibleTuple() static constexpr bool __valid_args()
&& { return (sizeof...(_Tail) + 2) == sizeof...(_Elements); }
!_TC2<_Dummy>::
_ImplicitlyDefaultConstructibleTuple(), /* Constraint for constructors with a tuple<UTypes...> parameter ensures
bool>::type = false> * that the constructor is only viable when it would not interfere with
explicit constexpr tuple() * tuple(UTypes&&...) or tuple(const tuple&) or tuple(tuple&&).
noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value) * Such constructors are only viable if:
: _Inherited() { } * either sizeof...(Types) != 1,
* or (when Types... expands to T and UTypes... expands to U)
// Shortcut for the cases where constructors taking _Elements... * is_convertible_v<TUPLE, T>, is_constructible_v<T, TUPLE>,
// need to be constrained. * and is_same_v<T, U> are all false.
template<typename _Dummy> using _TCC = */
_TC<is_same<_Dummy, void>::value, template<typename _Tuple, typename = tuple,
_Elements...>; typename = __remove_cvref_t<_Tuple>>
struct _UseOtherCtor
: false_type
{ };
// If TUPLE is convertible to the single element in *this,
// then TUPLE should match tuple(UTypes&&...) instead.
template<typename _Tuple, typename _Tp, typename _Up>
struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Up>>
: __or_<is_convertible<_Tuple, _Tp>, 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<typename _Tuple, typename _Tp>
struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Tp>>
: true_type
{ };
// Return true iff sizeof...(Types) == 1 && tuple_size_v<TUPLE> == 1
// and the single element in Types can be initialized from TUPLE,
// or is the same type as tuple_element_t<0, TUPLE>.
template<typename _Tuple>
static constexpr bool __use_other_ctor()
{ return _UseOtherCtor<_Tuple>::value; }
public:
template<typename _Dummy = void, template<typename _Dummy = void,
typename enable_if< _ImplicitDefaultCtor<is_void<_Dummy>::value> = true>
_TCC<_Dummy>::template constexpr
_ConstructibleTuple<_Elements...>() tuple()
&& _TCC<_Dummy>::template noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value)
_ImplicitlyConvertibleTuple<_Elements...>() : _Inherited() { }
&& (sizeof...(_Elements) >= 1),
bool>::type=true>
constexpr tuple(const _Elements&... __elements)
noexcept(__nothrow_constructible<const _Elements&...>())
: _Inherited(__elements...) { }
template<typename _Dummy = void, template<typename _Dummy = void,
typename enable_if< _ExplicitDefaultCtor<is_void<_Dummy>::value> = false>
_TCC<_Dummy>::template explicit constexpr
_ConstructibleTuple<_Elements...>() tuple()
&& !_TCC<_Dummy>::template noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value)
_ImplicitlyConvertibleTuple<_Elements...>() : _Inherited() { }
&& (sizeof...(_Elements) >= 1),
bool>::type=false> template<bool _NotEmpty = (sizeof...(_Elements) >= 1),
explicit constexpr tuple(const _Elements&... __elements) _ImplicitCtor<_NotEmpty, const _Elements&...> = true>
noexcept(__nothrow_constructible<const _Elements&...>()) constexpr
: _Inherited(__elements...) { } tuple(const _Elements&... __elements)
noexcept(__nothrow_constructible<const _Elements&...>())
// Shortcut for the cases where constructors taking _UElements... : _Inherited(__elements...) { }
// need to be constrained.
template<typename... _UElements> using _TMC = template<bool _NotEmpty = (sizeof...(_Elements) >= 1),
_TC<(sizeof...(_Elements) == sizeof...(_UElements)) _ExplicitCtor<_NotEmpty, const _Elements&...> = false>
&& (_TC<(sizeof...(_UElements)==1), _Elements...>:: explicit constexpr
template _NotSameTuple<_UElements...>()), tuple(const _Elements&... __elements)
_Elements...>; noexcept(__nothrow_constructible<const _Elements&...>())
: _Inherited(__elements...) { }
// Shortcut for the cases where constructors taking tuple<_UElements...>
// need to be constrained. template<typename... _UElements,
template<typename... _UElements> using _TMCT = bool _Valid = __valid_args<_UElements...>(),
_TC<(sizeof...(_Elements) == sizeof...(_UElements)) _ImplicitCtor<_Valid, _UElements...> = true>
&& !is_same<tuple<_Elements...>, constexpr
tuple<_UElements...>>::value, tuple(_UElements&&... __elements)
_Elements...>; noexcept(__nothrow_constructible<_UElements...>())
: _Inherited(std::forward<_UElements>(__elements)...) { }
template<typename... _UElements, typename
enable_if< template<typename... _UElements,
_TMC<_UElements...>::template bool _Valid = __valid_args<_UElements...>(),
_MoveConstructibleTuple<_UElements...>() _ExplicitCtor<_Valid, _UElements...> = false>
&& _TMC<_UElements...>::template explicit constexpr
_ImplicitlyMoveConvertibleTuple<_UElements...>() tuple(_UElements&&... __elements)
&& (sizeof...(_Elements) >= 1), noexcept(__nothrow_constructible<_UElements...>())
bool>::type=true>
constexpr tuple(_UElements&&... __elements)
noexcept(__nothrow_constructible<_UElements...>())
: _Inherited(std::forward<_UElements>(__elements)...) { }
template<typename... _UElements, typename
enable_if<
_TMC<_UElements...>::template
_MoveConstructibleTuple<_UElements...>()
&& !_TMC<_UElements...>::template
_ImplicitlyMoveConvertibleTuple<_UElements...>()
&& (sizeof...(_Elements) >= 1),
bool>::type=false>
explicit constexpr tuple(_UElements&&... __elements)
noexcept(__nothrow_constructible<_UElements...>())
: _Inherited(std::forward<_UElements>(__elements)...) { } : _Inherited(std::forward<_UElements>(__elements)...) { }
constexpr tuple(const tuple&) = default; constexpr tuple(const tuple&) = default;
constexpr tuple(tuple&&) = default; constexpr tuple(tuple&&) = default;
// Shortcut for the cases where constructors taking tuples template<typename... _UElements,
// must avoid creating temporaries. bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
template<typename _Dummy> using _TNTC = && !__use_other_ctor<const tuple<_UElements...>&>(),
_TC<is_same<_Dummy, void>::value && sizeof...(_Elements) == 1, _ImplicitCtor<_Valid, const _UElements&...> = true>
_Elements...>; constexpr
tuple(const tuple<_UElements...>& __in)
template<typename... _UElements, typename _Dummy = void, typename noexcept(__nothrow_constructible<const _UElements&...>())
enable_if<_TMCT<_UElements...>::template : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
_ConstructibleTuple<_UElements...>() { }
&& _TMCT<_UElements...>::template
_ImplicitlyConvertibleTuple<_UElements...>() template<typename... _UElements,
&& _TNTC<_Dummy>::template bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
_NonNestedTuple<const tuple<_UElements...>&>(), && !__use_other_ctor<const tuple<_UElements...>&>(),
bool>::type=true> _ExplicitCtor<_Valid, const _UElements&...> = false>
constexpr tuple(const tuple<_UElements...>& __in) explicit constexpr
noexcept(__nothrow_constructible<const _UElements&...>()) tuple(const tuple<_UElements...>& __in)
: _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) noexcept(__nothrow_constructible<const _UElements&...>())
{ } : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
{ }
template<typename... _UElements, typename _Dummy = void, typename
enable_if<_TMCT<_UElements...>::template template<typename... _UElements,
_ConstructibleTuple<_UElements...>() bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
&& !_TMCT<_UElements...>::template && !__use_other_ctor<tuple<_UElements...>&&>(),
_ImplicitlyConvertibleTuple<_UElements...>() _ImplicitCtor<_Valid, _UElements...> = true>
&& _TNTC<_Dummy>::template constexpr
_NonNestedTuple<const tuple<_UElements...>&>(), tuple(tuple<_UElements...>&& __in)
bool>::type=false> noexcept(__nothrow_constructible<_UElements...>())
explicit constexpr tuple(const tuple<_UElements...>& __in) : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
noexcept(__nothrow_constructible<const _UElements&...>())
: _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) template<typename... _UElements,
{ } bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
&& !__use_other_ctor<tuple<_UElements...>&&>(),
template<typename... _UElements, typename _Dummy = void, typename _ExplicitCtor<_Valid, _UElements...> = false>
enable_if<_TMCT<_UElements...>::template explicit constexpr
_MoveConstructibleTuple<_UElements...>() tuple(tuple<_UElements...>&& __in)
&& _TMCT<_UElements...>::template noexcept(__nothrow_constructible<_UElements...>())
_ImplicitlyMoveConvertibleTuple<_UElements...>() : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
&& _TNTC<_Dummy>::template
_NonNestedTuple<tuple<_UElements...>&&>(),
bool>::type=true>
constexpr tuple(tuple<_UElements...>&& __in)
noexcept(__nothrow_constructible<_UElements...>())
: _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
template<typename... _UElements, typename _Dummy = void, typename
enable_if<_TMCT<_UElements...>::template
_MoveConstructibleTuple<_UElements...>()
&& !_TMCT<_UElements...>::template
_ImplicitlyMoveConvertibleTuple<_UElements...>()
&& _TNTC<_Dummy>::template
_NonNestedTuple<tuple<_UElements...>&&>(),
bool>::type=false>
explicit constexpr tuple(tuple<_UElements...>&& __in)
noexcept(__nothrow_constructible<_UElements...>())
: _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
// Allocator-extended constructors. // Allocator-extended constructors.
template<typename _Alloc> template<typename _Alloc,
_ImplicitDefaultCtor<is_object<_Alloc>::value> = true>
tuple(allocator_arg_t __tag, const _Alloc& __a) tuple(allocator_arg_t __tag, const _Alloc& __a)
: _Inherited(__tag, __a) { } : _Inherited(__tag, __a) { }
template<typename _Alloc, typename _Dummy = void, template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1),
typename enable_if< _ImplicitCtor<_NotEmpty, const _Elements&...> = true>
_TCC<_Dummy>::template
_ConstructibleTuple<_Elements...>()
&& _TCC<_Dummy>::template
_ImplicitlyConvertibleTuple<_Elements...>(),
bool>::type=true>
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple(allocator_arg_t __tag, const _Alloc& __a,
const _Elements&... __elements) const _Elements&... __elements)
: _Inherited(__tag, __a, __elements...) { } : _Inherited(__tag, __a, __elements...) { }
template<typename _Alloc, typename _Dummy = void, template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1),
typename enable_if< _ExplicitCtor<_NotEmpty, const _Elements&...> = false>
_TCC<_Dummy>::template explicit
_ConstructibleTuple<_Elements...>() tuple(allocator_arg_t __tag, const _Alloc& __a,
&& !_TCC<_Dummy>::template const _Elements&... __elements)
_ImplicitlyConvertibleTuple<_Elements...>(),
bool>::type=false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
const _Elements&... __elements)
: _Inherited(__tag, __a, __elements...) { } : _Inherited(__tag, __a, __elements...) { }
template<typename _Alloc, typename... _UElements, typename template<typename _Alloc, typename... _UElements,
enable_if<_TMC<_UElements...>::template bool _Valid = __valid_args<_UElements...>(),
_MoveConstructibleTuple<_UElements...>() _ImplicitCtor<_Valid, _UElements...> = true>
&& _TMC<_UElements...>::template
_ImplicitlyMoveConvertibleTuple<_UElements...>(),
bool>::type=true>
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple(allocator_arg_t __tag, const _Alloc& __a,
_UElements&&... __elements) _UElements&&... __elements)
: _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...)
{ } { }
template<typename _Alloc, typename... _UElements, typename template<typename _Alloc, typename... _UElements,
enable_if<_TMC<_UElements...>::template bool _Valid = __valid_args<_UElements...>(),
_MoveConstructibleTuple<_UElements...>() _ExplicitCtor<_Valid, _UElements...> = false>
&& !_TMC<_UElements...>::template explicit
_ImplicitlyMoveConvertibleTuple<_UElements...>(), tuple(allocator_arg_t __tag, const _Alloc& __a,
bool>::type=false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
_UElements&&... __elements) _UElements&&... __elements)
: _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...)
{ } { }
template<typename _Alloc> template<typename _Alloc>
tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in)
...@@ -767,61 +721,43 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -767,61 +721,43 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in)
: _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { }
template<typename _Alloc, typename _Dummy = void, template<typename _Alloc, typename... _UElements,
typename... _UElements, typename bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
enable_if<_TMCT<_UElements...>::template && !__use_other_ctor<const tuple<_UElements...>&>(),
_ConstructibleTuple<_UElements...>() _ImplicitCtor<_Valid, const _UElements&...> = true>
&& _TMCT<_UElements...>::template
_ImplicitlyConvertibleTuple<_UElements...>()
&& _TNTC<_Dummy>::template
_NonNestedTuple<tuple<_UElements...>&&>(),
bool>::type=true>
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple(allocator_arg_t __tag, const _Alloc& __a,
const tuple<_UElements...>& __in) const tuple<_UElements...>& __in)
: _Inherited(__tag, __a, : _Inherited(__tag, __a,
static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
{ } { }
template<typename _Alloc, typename _Dummy = void, template<typename _Alloc, typename... _UElements,
typename... _UElements, typename bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
enable_if<_TMCT<_UElements...>::template && !__use_other_ctor<const tuple<_UElements...>&>(),
_ConstructibleTuple<_UElements...>() _ExplicitCtor<_Valid, const _UElements&...> = false>
&& !_TMCT<_UElements...>::template explicit
_ImplicitlyConvertibleTuple<_UElements...>() tuple(allocator_arg_t __tag, const _Alloc& __a,
&& _TNTC<_Dummy>::template
_NonNestedTuple<tuple<_UElements...>&&>(),
bool>::type=false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
const tuple<_UElements...>& __in) const tuple<_UElements...>& __in)
: _Inherited(__tag, __a, : _Inherited(__tag, __a,
static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
{ } { }
template<typename _Alloc, typename _Dummy = void, template<typename _Alloc, typename... _UElements,
typename... _UElements, typename bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
enable_if<_TMCT<_UElements...>::template && !__use_other_ctor<tuple<_UElements...>&&>(),
_MoveConstructibleTuple<_UElements...>() _ImplicitCtor<_Valid, _UElements...> = true>
&& _TMCT<_UElements...>::template
_ImplicitlyMoveConvertibleTuple<_UElements...>()
&& _TNTC<_Dummy>::template
_NonNestedTuple<tuple<_UElements...>&&>(),
bool>::type=true>
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple(allocator_arg_t __tag, const _Alloc& __a,
tuple<_UElements...>&& __in) tuple<_UElements...>&& __in)
: _Inherited(__tag, __a, : _Inherited(__tag, __a,
static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) static_cast<_Tuple_impl<0, _UElements...>&&>(__in))
{ } { }
template<typename _Alloc, typename _Dummy = void, template<typename _Alloc, typename... _UElements,
typename... _UElements, typename bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements))
enable_if<_TMCT<_UElements...>::template && !__use_other_ctor<tuple<_UElements...>&&>(),
_MoveConstructibleTuple<_UElements...>() _ExplicitCtor<_Valid, _UElements...> = false>
&& !_TMCT<_UElements...>::template explicit
_ImplicitlyMoveConvertibleTuple<_UElements...>() tuple(allocator_arg_t __tag, const _Alloc& __a,
&& _TNTC<_Dummy>::template
_NonNestedTuple<tuple<_UElements...>&&>(),
bool>::type=false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
tuple<_UElements...>&& __in) tuple<_UElements...>&& __in)
: _Inherited(__tag, __a, : _Inherited(__tag, __a,
static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) static_cast<_Tuple_impl<0, _UElements...>&&>(__in))
...@@ -910,6 +846,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -910,6 +846,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ {
typedef _Tuple_impl<0, _T1, _T2> _Inherited; typedef _Tuple_impl<0, _T1, _T2> _Inherited;
// Constraint for non-explicit default constructor
template<bool _Dummy, typename _U1, typename _U2>
using _ImplicitDefaultCtor = __enable_if_t<
_TupleConstraints<_Dummy, _U1, _U2>::
__is_implicitly_default_constructible(),
bool>;
// Constraint for explicit default constructor
template<bool _Dummy, typename _U1, typename _U2>
using _ExplicitDefaultCtor = __enable_if_t<
_TupleConstraints<_Dummy, _U1, _U2>::
__is_explicitly_default_constructible(),
bool>;
template<bool _Dummy>
using _TCC = _TupleConstraints<_Dummy, _T1, _T2>;
// Constraint for non-explicit constructors
template<bool _Cond, typename _U1, typename _U2>
using _ImplicitCtor = __enable_if_t<
_TCC<_Cond>::template __is_implicitly_constructible<_U1, _U2>(),
bool>;
// Constraint for non-explicit constructors
template<bool _Cond, typename _U1, typename _U2>
using _ExplicitCtor = __enable_if_t<
_TCC<_Cond>::template __is_explicitly_constructible<_U1, _U2>(),
bool>;
template<typename _U1, typename _U2> template<typename _U1, typename _U2>
static constexpr bool __assignable() static constexpr bool __assignable()
{ {
...@@ -937,215 +902,146 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -937,215 +902,146 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
is_nothrow_default_constructible<_T2>>::value; is_nothrow_default_constructible<_T2>>::value;
} }
template<typename _U1>
static constexpr bool __is_alloc_arg()
{ return is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value; }
public: public:
template <typename _U1 = _T1, template<bool _Dummy = true,
typename _U2 = _T2, _ImplicitDefaultCtor<_Dummy, _T1, _T2> = true>
typename enable_if<__and_< constexpr
__is_implicitly_default_constructible<_U1>, tuple()
__is_implicitly_default_constructible<_U2>>
::value, bool>::type = true>
constexpr tuple()
noexcept(__nothrow_default_constructible()) noexcept(__nothrow_default_constructible())
: _Inherited() { } : _Inherited() { }
template <typename _U1 = _T1, template<bool _Dummy = true,
typename _U2 = _T2, _ExplicitDefaultCtor<_Dummy, _T1, _T2> = false>
typename enable_if< explicit constexpr
__and_< tuple()
is_default_constructible<_U1>,
is_default_constructible<_U2>,
__not_<
__and_<__is_implicitly_default_constructible<_U1>,
__is_implicitly_default_constructible<_U2>>>>
::value, bool>::type = false>
explicit constexpr tuple()
noexcept(__nothrow_default_constructible()) noexcept(__nothrow_default_constructible())
: _Inherited() { } : _Inherited() { }
// Shortcut for the cases where constructors taking _T1, _T2 template<bool _Dummy = true,
// need to be constrained. _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true>
template<typename _Dummy> using _TCC = constexpr
_TC<is_same<_Dummy, void>::value, _T1, _T2>; tuple(const _T1& __a1, const _T2& __a2)
noexcept(__nothrow_constructible<const _T1&, const _T2&>())
template<typename _Dummy = void, typename : _Inherited(__a1, __a2) { }
enable_if<_TCC<_Dummy>::template
_ConstructibleTuple<_T1, _T2>() template<bool _Dummy = true,
&& _TCC<_Dummy>::template _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false>
_ImplicitlyConvertibleTuple<_T1, _T2>(), explicit constexpr
bool>::type = true> tuple(const _T1& __a1, const _T2& __a2)
constexpr tuple(const _T1& __a1, const _T2& __a2) noexcept(__nothrow_constructible<const _T1&, const _T2&>())
noexcept(__nothrow_constructible<const _T1&, const _T2&>()) : _Inherited(__a1, __a2) { }
: _Inherited(__a1, __a2) { }
template<typename _U1, typename _U2,
template<typename _Dummy = void, typename _ImplicitCtor<!__is_alloc_arg<_U1>(), _U1, _U2> = true>
enable_if<_TCC<_Dummy>::template constexpr
_ConstructibleTuple<_T1, _T2>() tuple(_U1&& __a1, _U2&& __a2)
&& !_TCC<_Dummy>::template noexcept(__nothrow_constructible<_U1, _U2>())
_ImplicitlyConvertibleTuple<_T1, _T2>(),
bool>::type = false>
explicit constexpr tuple(const _T1& __a1, const _T2& __a2)
noexcept(__nothrow_constructible<const _T1&, const _T2&>())
: _Inherited(__a1, __a2) { }
// Shortcut for the cases where constructors taking _U1, _U2
// need to be constrained.
using _TMC = _TC<true, _T1, _T2>;
template<typename _U1, typename _U2, typename
enable_if<_TMC::template
_MoveConstructibleTuple<_U1, _U2>()
&& _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>())
: _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<!__is_alloc_arg<_U1>(), _U1, _U2> = false>
_MoveConstructibleTuple<_U1, _U2>() explicit constexpr
&& !_TMC::template tuple(_U1&& __a1, _U2&& __a2)
_ImplicitlyMoveConvertibleTuple<_U1, _U2>() noexcept(__nothrow_constructible<_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>())
: _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
constexpr tuple(const tuple&) = default; constexpr tuple(const tuple&) = default;
constexpr tuple(tuple&&) = default; constexpr tuple(tuple&&) = default;
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, const _U1&, const _U2&> = true>
_ConstructibleTuple<_U1, _U2>() constexpr
&& _TMC::template tuple(const tuple<_U1, _U2>& __in)
_ImplicitlyConvertibleTuple<_U1, _U2>(), noexcept(__nothrow_constructible<const _U1&, const _U2&>())
bool>::type = true>
constexpr tuple(const tuple<_U1, _U2>& __in)
noexcept(__nothrow_constructible<const _U1&, const _U2&>())
: _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { }
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, const _U1&, const _U2&> = false>
_ConstructibleTuple<_U1, _U2>() explicit constexpr
&& !_TMC::template tuple(const tuple<_U1, _U2>& __in)
_ImplicitlyConvertibleTuple<_U1, _U2>(), noexcept(__nothrow_constructible<const _U1&, const _U2&>())
bool>::type = false>
explicit constexpr tuple(const tuple<_U1, _U2>& __in)
noexcept(__nothrow_constructible<const _U1&, const _U2&>())
: _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { }
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, _U1, _U2> = true>
_MoveConstructibleTuple<_U1, _U2>() constexpr
&& _TMC::template tuple(tuple<_U1, _U2>&& __in)
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(), noexcept(__nothrow_constructible<_U1, _U2>())
bool>::type = true>
constexpr tuple(tuple<_U1, _U2>&& __in)
noexcept(__nothrow_constructible<_U1, _U2>())
: _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { }
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, _U1, _U2> = false>
_MoveConstructibleTuple<_U1, _U2>() explicit constexpr
&& !_TMC::template tuple(tuple<_U1, _U2>&& __in)
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(), noexcept(__nothrow_constructible<_U1, _U2>())
bool>::type = false>
explicit constexpr tuple(tuple<_U1, _U2>&& __in)
noexcept(__nothrow_constructible<_U1, _U2>())
: _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { }
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, const _U1&, const _U2&> = true>
_ConstructibleTuple<_U1, _U2>() constexpr
&& _TMC::template tuple(const pair<_U1, _U2>& __in)
_ImplicitlyConvertibleTuple<_U1, _U2>(), noexcept(__nothrow_constructible<const _U1&, const _U2&>())
bool>::type = true>
constexpr tuple(const pair<_U1, _U2>& __in)
noexcept(__nothrow_constructible<const _U1&, const _U2&>())
: _Inherited(__in.first, __in.second) { } : _Inherited(__in.first, __in.second) { }
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, const _U1&, const _U2&> = false>
_ConstructibleTuple<_U1, _U2>() explicit constexpr
&& !_TMC::template tuple(const pair<_U1, _U2>& __in)
_ImplicitlyConvertibleTuple<_U1, _U2>(), noexcept(__nothrow_constructible<const _U1&, const _U2&>())
bool>::type = false>
explicit constexpr tuple(const pair<_U1, _U2>& __in)
noexcept(__nothrow_constructible<const _U1&, const _U2&>())
: _Inherited(__in.first, __in.second) { } : _Inherited(__in.first, __in.second) { }
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, _U1, _U2> = true>
_MoveConstructibleTuple<_U1, _U2>() constexpr
&& _TMC::template tuple(pair<_U1, _U2>&& __in)
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(), noexcept(__nothrow_constructible<_U1, _U2>())
bool>::type = true>
constexpr tuple(pair<_U1, _U2>&& __in)
noexcept(__nothrow_constructible<_U1, _U2>())
: _Inherited(std::forward<_U1>(__in.first), : _Inherited(std::forward<_U1>(__in.first),
std::forward<_U2>(__in.second)) { } std::forward<_U2>(__in.second)) { }
template<typename _U1, typename _U2, typename template<typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, _U1, _U2> = false>
_MoveConstructibleTuple<_U1, _U2>() explicit constexpr
&& !_TMC::template tuple(pair<_U1, _U2>&& __in)
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(), noexcept(__nothrow_constructible<_U1, _U2>())
bool>::type = false>
explicit constexpr tuple(pair<_U1, _U2>&& __in)
noexcept(__nothrow_constructible<_U1, _U2>())
: _Inherited(std::forward<_U1>(__in.first), : _Inherited(std::forward<_U1>(__in.first),
std::forward<_U2>(__in.second)) { } std::forward<_U2>(__in.second)) { }
// Allocator-extended constructors. // Allocator-extended constructors.
template<typename _Alloc> template<typename _Alloc,
_ImplicitDefaultCtor<is_object<_Alloc>::value, _T1, _T2> = true>
tuple(allocator_arg_t __tag, const _Alloc& __a) tuple(allocator_arg_t __tag, const _Alloc& __a)
: _Inherited(__tag, __a) { } : _Inherited(__tag, __a) { }
template<typename _Alloc, typename _Dummy = void, template<typename _Alloc, bool _Dummy = true,
typename enable_if< _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true>
_TCC<_Dummy>::template
_ConstructibleTuple<_T1, _T2>()
&& _TCC<_Dummy>::template
_ImplicitlyConvertibleTuple<_T1, _T2>(),
bool>::type=true>
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple(allocator_arg_t __tag, const _Alloc& __a,
const _T1& __a1, const _T2& __a2) const _T1& __a1, const _T2& __a2)
: _Inherited(__tag, __a, __a1, __a2) { } : _Inherited(__tag, __a, __a1, __a2) { }
template<typename _Alloc, typename _Dummy = void, template<typename _Alloc, bool _Dummy = true,
typename enable_if< _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false>
_TCC<_Dummy>::template explicit
_ConstructibleTuple<_T1, _T2>() tuple(allocator_arg_t __tag, const _Alloc& __a,
&& !_TCC<_Dummy>::template
_ImplicitlyConvertibleTuple<_T1, _T2>(),
bool>::type=false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
const _T1& __a1, const _T2& __a2) const _T1& __a1, const _T2& __a2)
: _Inherited(__tag, __a, __a1, __a2) { } : _Inherited(__tag, __a, __a1, __a2) { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, _U1, _U2> = true>
_MoveConstructibleTuple<_U1, _U2>()
&& _TMC::template
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(),
bool>::type = true>
tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2) tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2)
: _Inherited(__tag, __a, std::forward<_U1>(__a1), : _Inherited(__tag, __a, std::forward<_U1>(__a1),
std::forward<_U2>(__a2)) { } std::forward<_U2>(__a2)) { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, _U1, _U2> = false>
_MoveConstructibleTuple<_U1, _U2>() explicit
&& !_TMC::template tuple(allocator_arg_t __tag, const _Alloc& __a,
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(), _U1&& __a1, _U2&& __a2)
bool>::type = false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
_U1&& __a1, _U2&& __a2)
: _Inherited(__tag, __a, std::forward<_U1>(__a1), : _Inherited(__tag, __a, std::forward<_U1>(__a1),
std::forward<_U2>(__a2)) { } std::forward<_U2>(__a2)) { }
...@@ -1157,89 +1053,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1157,89 +1053,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in)
: _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, const _U1&, const _U2&> = true>
_ConstructibleTuple<_U1, _U2>()
&& _TMC::template
_ImplicitlyConvertibleTuple<_U1, _U2>(),
bool>::type = true>
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple(allocator_arg_t __tag, const _Alloc& __a,
const tuple<_U1, _U2>& __in) const tuple<_U1, _U2>& __in)
: _Inherited(__tag, __a, : _Inherited(__tag, __a,
static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in))
{ } { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, const _U1&, const _U2&> = false>
_ConstructibleTuple<_U1, _U2>() explicit
&& !_TMC::template tuple(allocator_arg_t __tag, const _Alloc& __a,
_ImplicitlyConvertibleTuple<_U1, _U2>(),
bool>::type = false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
const tuple<_U1, _U2>& __in) const tuple<_U1, _U2>& __in)
: _Inherited(__tag, __a, : _Inherited(__tag, __a,
static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in))
{ } { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, _U1, _U2> = true>
_MoveConstructibleTuple<_U1, _U2>()
&& _TMC::template
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(),
bool>::type = true>
tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in)
: _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in))
{ } { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, _U1, _U2> = false>
_MoveConstructibleTuple<_U1, _U2>() explicit
&& !_TMC::template tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in)
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(),
bool>::type = 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)) : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in))
{ } { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, const _U1&, const _U2&> = true>
_ConstructibleTuple<_U1, _U2>() tuple(allocator_arg_t __tag, const _Alloc& __a,
&& _TMC::template
_ImplicitlyConvertibleTuple<_U1, _U2>(),
bool>::type = true>
tuple(allocator_arg_t __tag, const _Alloc& __a,
const pair<_U1, _U2>& __in) const pair<_U1, _U2>& __in)
: _Inherited(__tag, __a, __in.first, __in.second) { } : _Inherited(__tag, __a, __in.first, __in.second) { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, const _U1&, const _U2&> = false>
_ConstructibleTuple<_U1, _U2>() explicit
&& !_TMC::template tuple(allocator_arg_t __tag, const _Alloc& __a,
_ImplicitlyConvertibleTuple<_U1, _U2>(),
bool>::type = false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
const pair<_U1, _U2>& __in) const pair<_U1, _U2>& __in)
: _Inherited(__tag, __a, __in.first, __in.second) { } : _Inherited(__tag, __a, __in.first, __in.second) { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ImplicitCtor<true, _U1, _U2> = true>
_MoveConstructibleTuple<_U1, _U2>() tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
&& _TMC::template
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(),
bool>::type = true>
tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
: _Inherited(__tag, __a, std::forward<_U1>(__in.first), : _Inherited(__tag, __a, std::forward<_U1>(__in.first),
std::forward<_U2>(__in.second)) { } std::forward<_U2>(__in.second)) { }
template<typename _Alloc, typename _U1, typename _U2, typename template<typename _Alloc, typename _U1, typename _U2,
enable_if<_TMC::template _ExplicitCtor<true, _U1, _U2> = false>
_MoveConstructibleTuple<_U1, _U2>() explicit
&& !_TMC::template tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in)
_ImplicitlyMoveConvertibleTuple<_U1, _U2>(),
bool>::type = false>
explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
pair<_U1, _U2>&& __in)
: _Inherited(__tag, __a, std::forward<_U1>(__in.first), : _Inherited(__tag, __a, std::forward<_U1>(__in.first),
std::forward<_U2>(__in.second)) { } std::forward<_U2>(__in.second)) { }
......
// 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
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++11 } }
#include <tuple>
#include <memory>
struct X { };
struct Y
{
Y(const std::tuple<X>&) = delete;
Y(std::tuple<X>&&) { throw 1; }
Y(const X&) { }
};
struct Z
{
Z(X&&) { }
Z(const std::tuple<X>&) { throw 1; }
Z(std::tuple<X>&&) = delete;
};
void
test01()
{
// PR libstdc++/90700 wrong constraints on constructor
const std::allocator<int> a;
const std::tuple<X> x;
static_assert(!std::is_convertible<const std::tuple<X>&, Y>::value, "");
static_assert(!std::is_constructible<Y, const std::tuple<X>&>::value, "");
static_assert(!std::is_same<Y, X>::value, "");
// should use tuple<Y>::tuple<X>(allocator_arg_t, const A&, const tuple<X>&)
// and construct Y from X:
std::tuple<Y> y(std::allocator_arg, a, x);
}
void
test02()
{
const std::allocator<int> a;
std::tuple<X> x;
static_assert(!std::is_convertible<std::tuple<X>, Z>::value, "");
static_assert(!std::is_constructible<Z, std::tuple<X>>::value, "");
static_assert(!std::is_same<Z, X>::value, "");
// should use tuple<Z>::tuple<X>(allocator_arg_t, const A&, tuple<X>&&)
// and construct Z from X:
std::tuple<Z> z(std::allocator_arg, a, std::move(x));
}
...@@ -186,12 +186,26 @@ void test03() ...@@ -186,12 +186,26 @@ void test03()
struct dr2586 struct dr2586
{ {
using allocator_type = std::allocator<int>; using allocator_type = std::allocator<int>;
dr2586() { }
dr2586(std::allocator_arg_t, allocator_type&&) { } 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; const dr2586::allocator_type a;
std::tuple<dr2586> t{std::allocator_arg, a}; std::tuple<dr2586> 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<X, void(&)()> t(std::allocator_arg, *+[]{});
} }
int main() int main()
...@@ -199,5 +213,6 @@ int main() ...@@ -199,5 +213,6 @@ int main()
test01(); test01();
test02(); test02();
test03(); test03();
test04();
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment