PR libstdc++/86963 Remove use of __tuple_base in std::tuple
The _Tuple_impl base class can be used to disable copy/move assignment, without requiring an extra base class. Exception specifications on std::tuple assignment and swap functions can be defined directly using is_nothrow_swappable, instead of querying the base classes. PR libstdc++/86963 * include/std/tuple (_Tuple_impl::operator=): Define as deleted. (_Tuple_impl::_M_assign): New functions to perform assignment instead of assignment operators. (_Tuple_impl::_M_swap): Remove exception specification. (_Tuple_impl<_Idx, _Head>): Likewise. (_TC::_NonNestedTuple, _TC::_NotSameTuple): Use __remove_cvref_t. (__tuple_base): Remove. (tuple, tuple<_T1, _T2>): Remove inheritance from __tuple_base. (tuple::operator=, tuple<_T1, _T2>::operator=): Call _M_assign. (tuple::swap, tuple<_T1, _T2>::swap): Define exception specification using __is_nothrow_swappable. (tuple<_T1, _T2>::tuple(_U1&&, _U2&&)): Use __remove_cvref_t. From-SVN: r263661
This commit is contained in:
parent
ea379c9ec3
commit
a2c5e1ae59
|
@ -1,5 +1,19 @@
|
||||||
2018-08-20 Jonathan Wakely <jwakely@redhat.com>
|
2018-08-20 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
|
PR libstdc++/86963
|
||||||
|
* include/std/tuple (_Tuple_impl::operator=): Define as deleted.
|
||||||
|
(_Tuple_impl::_M_assign): New functions to perform assignment instead
|
||||||
|
of assignment operators.
|
||||||
|
(_Tuple_impl::_M_swap): Remove exception specification.
|
||||||
|
(_Tuple_impl<_Idx, _Head>): Likewise.
|
||||||
|
(_TC::_NonNestedTuple, _TC::_NotSameTuple): Use __remove_cvref_t.
|
||||||
|
(__tuple_base): Remove.
|
||||||
|
(tuple, tuple<_T1, _T2>): Remove inheritance from __tuple_base.
|
||||||
|
(tuple::operator=, tuple<_T1, _T2>::operator=): Call _M_assign.
|
||||||
|
(tuple::swap, tuple<_T1, _T2>::swap): Define exception specification
|
||||||
|
using __is_nothrow_swappable.
|
||||||
|
(tuple<_T1, _T2>::tuple(_U1&&, _U2&&)): Use __remove_cvref_t.
|
||||||
|
|
||||||
* include/std/optional (_Optional_payload): Use variable templates
|
* include/std/optional (_Optional_payload): Use variable templates
|
||||||
for conditions in default template arguments and exception
|
for conditions in default template arguments and exception
|
||||||
specifications.
|
specifications.
|
||||||
|
|
|
@ -219,6 +219,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
|
|
||||||
constexpr _Tuple_impl(const _Tuple_impl&) = default;
|
constexpr _Tuple_impl(const _Tuple_impl&) = default;
|
||||||
|
|
||||||
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
|
// 2729. Missing SFINAE on std::pair::operator=
|
||||||
|
_Tuple_impl& operator=(const _Tuple_impl&) = delete;
|
||||||
|
|
||||||
constexpr
|
constexpr
|
||||||
_Tuple_impl(_Tuple_impl&& __in)
|
_Tuple_impl(_Tuple_impl&& __in)
|
||||||
noexcept(__and_<is_nothrow_move_constructible<_Head>,
|
noexcept(__and_<is_nothrow_move_constructible<_Head>,
|
||||||
|
@ -288,49 +292,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
std::forward<_UHead>
|
std::forward<_UHead>
|
||||||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { }
|
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { }
|
||||||
|
|
||||||
_Tuple_impl&
|
|
||||||
operator=(const _Tuple_impl& __in)
|
|
||||||
{
|
|
||||||
_M_head(*this) = _M_head(__in);
|
|
||||||
_M_tail(*this) = _M_tail(__in);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Tuple_impl&
|
|
||||||
operator=(_Tuple_impl&& __in)
|
|
||||||
noexcept(__and_<is_nothrow_move_assignable<_Head>,
|
|
||||||
is_nothrow_move_assignable<_Inherited>>::value)
|
|
||||||
{
|
|
||||||
_M_head(*this) = std::forward<_Head>(_M_head(__in));
|
|
||||||
_M_tail(*this) = std::move(_M_tail(__in));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... _UElements>
|
template<typename... _UElements>
|
||||||
_Tuple_impl&
|
void
|
||||||
operator=(const _Tuple_impl<_Idx, _UElements...>& __in)
|
_M_assign(const _Tuple_impl<_Idx, _UElements...>& __in)
|
||||||
{
|
{
|
||||||
_M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in);
|
_M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in);
|
||||||
_M_tail(*this) = _Tuple_impl<_Idx, _UElements...>::_M_tail(__in);
|
_M_tail(*this)._M_assign(
|
||||||
return *this;
|
_Tuple_impl<_Idx, _UElements...>::_M_tail(__in));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename _UHead, typename... _UTails>
|
template<typename _UHead, typename... _UTails>
|
||||||
_Tuple_impl&
|
void
|
||||||
operator=(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
|
_M_assign(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
|
||||||
{
|
{
|
||||||
_M_head(*this) = std::forward<_UHead>
|
_M_head(*this) = std::forward<_UHead>
|
||||||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in));
|
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in));
|
||||||
_M_tail(*this) = std::move
|
_M_tail(*this)._M_assign(
|
||||||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in));
|
std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)));
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void
|
void
|
||||||
_M_swap(_Tuple_impl& __in)
|
_M_swap(_Tuple_impl& __in)
|
||||||
noexcept(__is_nothrow_swappable<_Head>::value
|
|
||||||
&& noexcept(_M_tail(__in)._M_swap(_M_tail(__in))))
|
|
||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(_M_head(*this), _M_head(__in));
|
swap(_M_head(*this), _M_head(__in));
|
||||||
|
@ -367,6 +350,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
|
|
||||||
constexpr _Tuple_impl(const _Tuple_impl&) = default;
|
constexpr _Tuple_impl(const _Tuple_impl&) = default;
|
||||||
|
|
||||||
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
|
// 2729. Missing SFINAE on std::pair::operator=
|
||||||
|
_Tuple_impl& operator=(const _Tuple_impl&) = delete;
|
||||||
|
|
||||||
constexpr
|
constexpr
|
||||||
_Tuple_impl(_Tuple_impl&& __in)
|
_Tuple_impl(_Tuple_impl&& __in)
|
||||||
noexcept(is_nothrow_move_constructible<_Head>::value)
|
noexcept(is_nothrow_move_constructible<_Head>::value)
|
||||||
|
@ -420,42 +407,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
|
std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
_Tuple_impl&
|
|
||||||
operator=(const _Tuple_impl& __in)
|
|
||||||
{
|
|
||||||
_M_head(*this) = _M_head(__in);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Tuple_impl&
|
|
||||||
operator=(_Tuple_impl&& __in)
|
|
||||||
noexcept(is_nothrow_move_assignable<_Head>::value)
|
|
||||||
{
|
|
||||||
_M_head(*this) = std::forward<_Head>(_M_head(__in));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename _UHead>
|
template<typename _UHead>
|
||||||
_Tuple_impl&
|
void
|
||||||
operator=(const _Tuple_impl<_Idx, _UHead>& __in)
|
_M_assign(const _Tuple_impl<_Idx, _UHead>& __in)
|
||||||
{
|
{
|
||||||
_M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in);
|
_M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in);
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename _UHead>
|
template<typename _UHead>
|
||||||
_Tuple_impl&
|
void
|
||||||
operator=(_Tuple_impl<_Idx, _UHead>&& __in)
|
_M_assign(_Tuple_impl<_Idx, _UHead>&& __in)
|
||||||
{
|
{
|
||||||
_M_head(*this)
|
_M_head(*this)
|
||||||
= std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in));
|
= std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in));
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void
|
void
|
||||||
_M_swap(_Tuple_impl& __in)
|
_M_swap(_Tuple_impl& __in)
|
||||||
noexcept(__is_nothrow_swappable<_Head>::value)
|
|
||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(_M_head(*this), _M_head(__in));
|
swap(_M_head(*this), _M_head(__in));
|
||||||
|
@ -495,20 +464,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
static constexpr bool _NonNestedTuple()
|
static constexpr bool _NonNestedTuple()
|
||||||
{
|
{
|
||||||
return __and_<__not_<is_same<tuple<_Elements...>,
|
return __and_<__not_<is_same<tuple<_Elements...>,
|
||||||
typename remove_cv<
|
__remove_cvref_t<_SrcTuple>>>,
|
||||||
typename remove_reference<_SrcTuple>::type
|
|
||||||
>::type>>,
|
|
||||||
__not_<is_convertible<_SrcTuple, _Elements...>>,
|
__not_<is_convertible<_SrcTuple, _Elements...>>,
|
||||||
__not_<is_constructible<_Elements..., _SrcTuple>>
|
__not_<is_constructible<_Elements..., _SrcTuple>>
|
||||||
>::value;
|
>::value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... _UElements>
|
template<typename... _UElements>
|
||||||
static constexpr bool _NotSameTuple()
|
static constexpr bool _NotSameTuple()
|
||||||
{
|
{
|
||||||
return __not_<is_same<tuple<_Elements...>,
|
return __not_<is_same<tuple<_Elements...>,
|
||||||
typename remove_const<
|
__remove_cvref_t<_UElements>...>>::value;
|
||||||
typename remove_reference<_UElements...>::type
|
|
||||||
>::type>>::value;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -544,30 +510,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... _UElements>
|
template<typename... _UElements>
|
||||||
static constexpr bool _NotSameTuple()
|
static constexpr bool _NotSameTuple()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The tag parameter ensures that in nested tuples each __tuple_base
|
|
||||||
// is a different type and can use the empty base-class optimisation.
|
|
||||||
template<typename _Tag>
|
|
||||||
class __tuple_base
|
|
||||||
{
|
|
||||||
template<typename...> friend struct tuple;
|
|
||||||
__tuple_base() = default;
|
|
||||||
~__tuple_base() = default;
|
|
||||||
__tuple_base(const __tuple_base&) = default;
|
|
||||||
__tuple_base& operator=(const __tuple_base&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Primary class template, tuple
|
/// Primary class template, tuple
|
||||||
template<typename... _Elements>
|
template<typename... _Elements>
|
||||||
class tuple
|
class tuple : public _Tuple_impl<0, _Elements...>
|
||||||
: public _Tuple_impl<0, _Elements...>,
|
|
||||||
private __tuple_base<tuple<_Elements...>>
|
|
||||||
{
|
{
|
||||||
typedef _Tuple_impl<0, _Elements...> _Inherited;
|
typedef _Tuple_impl<0, _Elements...> _Inherited;
|
||||||
|
|
||||||
|
@ -858,13 +811,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
static_cast<_Tuple_impl<0, _UElements...>&&>(__in))
|
static_cast<_Tuple_impl<0, _UElements...>&&>(__in))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
// tuple assignment
|
||||||
|
|
||||||
tuple&
|
tuple&
|
||||||
operator=(typename conditional<__assignable<const _Elements&...>(),
|
operator=(typename conditional<__assignable<const _Elements&...>(),
|
||||||
const tuple&,
|
const tuple&,
|
||||||
const __nonesuch_no_braces&>::type __in)
|
const __nonesuch_no_braces&>::type __in)
|
||||||
noexcept(__nothrow_assignable<const _Elements&...>())
|
noexcept(__nothrow_assignable<const _Elements&...>())
|
||||||
{
|
{
|
||||||
static_cast<_Inherited&>(*this) = __in;
|
this->_M_assign(__in);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,7 +829,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
__nonesuch_no_braces&&>::type __in)
|
__nonesuch_no_braces&&>::type __in)
|
||||||
noexcept(__nothrow_assignable<_Elements...>())
|
noexcept(__nothrow_assignable<_Elements...>())
|
||||||
{
|
{
|
||||||
static_cast<_Inherited&>(*this) = std::move(__in);
|
this->_M_assign(std::move(__in));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -883,7 +838,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
operator=(const tuple<_UElements...>& __in)
|
operator=(const tuple<_UElements...>& __in)
|
||||||
noexcept(__nothrow_assignable<const _UElements&...>())
|
noexcept(__nothrow_assignable<const _UElements&...>())
|
||||||
{
|
{
|
||||||
static_cast<_Inherited&>(*this) = __in;
|
this->_M_assign(__in);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -892,13 +847,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
operator=(tuple<_UElements...>&& __in)
|
operator=(tuple<_UElements...>&& __in)
|
||||||
noexcept(__nothrow_assignable<_UElements...>())
|
noexcept(__nothrow_assignable<_UElements...>())
|
||||||
{
|
{
|
||||||
static_cast<_Inherited&>(*this) = std::move(__in);
|
this->_M_assign(std::move(__in));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tuple swap
|
||||||
void
|
void
|
||||||
swap(tuple& __in)
|
swap(tuple& __in)
|
||||||
noexcept(noexcept(__in._M_swap(__in)))
|
noexcept(__and_<__is_nothrow_swappable<_Elements>...>::value)
|
||||||
{ _Inherited::_M_swap(__in); }
|
{ _Inherited::_M_swap(__in); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -934,9 +890,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
/// Partial specialization, 2-element tuple.
|
/// Partial specialization, 2-element tuple.
|
||||||
/// Includes construction and assignment from a pair.
|
/// Includes construction and assignment from a pair.
|
||||||
template<typename _T1, typename _T2>
|
template<typename _T1, typename _T2>
|
||||||
class tuple<_T1, _T2>
|
class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2>
|
||||||
: public _Tuple_impl<0, _T1, _T2>,
|
|
||||||
private __tuple_base<tuple<_T1, _T2>>
|
|
||||||
{
|
{
|
||||||
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
|
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
|
||||||
|
|
||||||
|
@ -1009,8 +963,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
_MoveConstructibleTuple<_U1, _U2>()
|
_MoveConstructibleTuple<_U1, _U2>()
|
||||||
&& _TMC::template
|
&& _TMC::template
|
||||||
_ImplicitlyMoveConvertibleTuple<_U1, _U2>()
|
_ImplicitlyMoveConvertibleTuple<_U1, _U2>()
|
||||||
&& !is_same<typename decay<_U1>::type,
|
&& !is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value,
|
||||||
allocator_arg_t>::value,
|
|
||||||
bool>::type = true>
|
bool>::type = true>
|
||||||
constexpr tuple(_U1&& __a1, _U2&& __a2)
|
constexpr tuple(_U1&& __a1, _U2&& __a2)
|
||||||
: _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
|
: _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
|
||||||
|
@ -1020,8 +973,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
_MoveConstructibleTuple<_U1, _U2>()
|
_MoveConstructibleTuple<_U1, _U2>()
|
||||||
&& !_TMC::template
|
&& !_TMC::template
|
||||||
_ImplicitlyMoveConvertibleTuple<_U1, _U2>()
|
_ImplicitlyMoveConvertibleTuple<_U1, _U2>()
|
||||||
&& !is_same<typename decay<_U1>::type,
|
&& !is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value,
|
||||||
allocator_arg_t>::value,
|
|
||||||
bool>::type = false>
|
bool>::type = false>
|
||||||
explicit constexpr tuple(_U1&& __a1, _U2&& __a2)
|
explicit constexpr tuple(_U1&& __a1, _U2&& __a2)
|
||||||
: _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
|
: _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
|
||||||
|
@ -1255,7 +1207,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
const __nonesuch_no_braces&>::type __in)
|
const __nonesuch_no_braces&>::type __in)
|
||||||
noexcept(__nothrow_assignable<const _T1&, const _T2&>())
|
noexcept(__nothrow_assignable<const _T1&, const _T2&>())
|
||||||
{
|
{
|
||||||
static_cast<_Inherited&>(*this) = __in;
|
this->_M_assign(__in);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1265,7 +1217,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
__nonesuch_no_braces&&>::type __in)
|
__nonesuch_no_braces&&>::type __in)
|
||||||
noexcept(__nothrow_assignable<_T1, _T2>())
|
noexcept(__nothrow_assignable<_T1, _T2>())
|
||||||
{
|
{
|
||||||
static_cast<_Inherited&>(*this) = std::move(__in);
|
this->_M_assign(std::move(__in));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1274,7 +1226,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
operator=(const tuple<_U1, _U2>& __in)
|
operator=(const tuple<_U1, _U2>& __in)
|
||||||
noexcept(__nothrow_assignable<const _U1&, const _U2&>())
|
noexcept(__nothrow_assignable<const _U1&, const _U2&>())
|
||||||
{
|
{
|
||||||
static_cast<_Inherited&>(*this) = __in;
|
this->_M_assign(__in);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1283,7 +1235,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
operator=(tuple<_U1, _U2>&& __in)
|
operator=(tuple<_U1, _U2>&& __in)
|
||||||
noexcept(__nothrow_assignable<_U1, _U2>())
|
noexcept(__nothrow_assignable<_U1, _U2>())
|
||||||
{
|
{
|
||||||
static_cast<_Inherited&>(*this) = std::move(__in);
|
this->_M_assign(std::move(__in));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,7 +1261,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
|
|
||||||
void
|
void
|
||||||
swap(tuple& __in)
|
swap(tuple& __in)
|
||||||
noexcept(noexcept(__in._M_swap(__in)))
|
noexcept(__and_<__is_nothrow_swappable<_T1>,
|
||||||
|
__is_nothrow_swappable<_T2>>::value)
|
||||||
{ _Inherited::_M_swap(__in); }
|
{ _Inherited::_M_swap(__in); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue