}
};
+ // 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
template<typename... _Elements>
- class tuple : public _Tuple_impl<0, _Elements...>
+ class tuple
+ : public _Tuple_impl<0, _Elements...>,
+ private __tuple_base<tuple<_Elements...>>
{
typedef _Tuple_impl<0, _Elements...> _Inherited;
}
};
+ template<typename... _UElements>
+ static constexpr
+ __enable_if_t<sizeof...(_UElements) == sizeof...(_Elements), bool>
+ __assignable()
+ { return __and_<is_assignable<_Elements&, _UElements>...>::value; }
+
+ template<typename... _UElements>
+ static constexpr bool __nothrow_assignable()
+ {
+ return
+ __and_<is_nothrow_assignable<_Elements&, _UElements>...>::value;
+ }
+
public:
template<typename _Dummy = void,
typename enable_if<_TC2<_Dummy>::
{ }
tuple&
- operator=(const tuple& __in)
+ operator=(typename conditional<__assignable<const _Elements&...>(),
+ const tuple&,
+ const __nonesuch_no_braces&>::type __in)
+ noexcept(__nothrow_assignable<const _Elements&...>())
{
static_cast<_Inherited&>(*this) = __in;
return *this;
}
tuple&
- operator=(tuple&& __in)
- noexcept(is_nothrow_move_assignable<_Inherited>::value)
+ operator=(typename conditional<__assignable<_Elements...>(),
+ tuple&&,
+ __nonesuch_no_braces&&>::type __in)
+ noexcept(__nothrow_assignable<_Elements...>())
{
static_cast<_Inherited&>(*this) = std::move(__in);
return *this;
}
template<typename... _UElements>
- typename
- enable_if<sizeof...(_UElements)
- == sizeof...(_Elements), tuple&>::type
- operator=(const tuple<_UElements...>& __in)
- {
+ __enable_if_t<__assignable<const _UElements&...>(), tuple&>
+ operator=(const tuple<_UElements...>& __in)
+ noexcept(__nothrow_assignable<const _UElements&...>())
+ {
static_cast<_Inherited&>(*this) = __in;
return *this;
}
template<typename... _UElements>
- typename
- enable_if<sizeof...(_UElements)
- == sizeof...(_Elements), tuple&>::type
- operator=(tuple<_UElements...>&& __in)
- {
+ __enable_if_t<__assignable<_UElements...>(), tuple&>
+ operator=(tuple<_UElements...>&& __in)
+ noexcept(__nothrow_assignable<_UElements...>())
+ {
static_cast<_Inherited&>(*this) = std::move(__in);
return *this;
}
/// Partial specialization, 2-element tuple.
/// Includes construction and assignment from a pair.
template<typename _T1, typename _T2>
- class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2>
+ class tuple<_T1, _T2>
+ : public _Tuple_impl<0, _T1, _T2>,
+ private __tuple_base<tuple<_T1, _T2>>
{
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
+ template<typename _U1, typename _U2>
+ static constexpr bool __assignable()
+ {
+ return __and_<is_assignable<_T1&, _U1>,
+ is_assignable<_T2&, _U2>>::value;
+ }
+
+ template<typename _U1, typename _U2>
+ static constexpr bool __nothrow_assignable()
+ {
+ return __and_<is_nothrow_assignable<_T1&, _U1>,
+ is_nothrow_assignable<_T2&, _U2>>::value;
+ }
+
public:
template <typename _U1 = _T1,
typename _U2 = _T2,
__is_implicitly_default_constructible<_U1>,
__is_implicitly_default_constructible<_U2>>
::value, bool>::type = true>
-
- constexpr tuple()
- : _Inherited() { }
+ constexpr tuple()
+ : _Inherited() { }
template <typename _U1 = _T1,
typename _U2 = _T2,
__and_<__is_implicitly_default_constructible<_U1>,
__is_implicitly_default_constructible<_U2>>>>
::value, bool>::type = false>
-
- explicit constexpr tuple()
- : _Inherited() { }
+ explicit constexpr tuple()
+ : _Inherited() { }
// Shortcut for the cases where constructors taking _T1, _T2
// need to be constrained.
std::forward<_U2>(__in.second)) { }
tuple&
- operator=(const tuple& __in)
+ operator=(typename conditional<__assignable<const _T1&, const _T2&>(),
+ const tuple&,
+ const __nonesuch_no_braces&>::type __in)
+ noexcept(__nothrow_assignable<const _T1&, const _T2&>())
{
static_cast<_Inherited&>(*this) = __in;
return *this;
}
tuple&
- operator=(tuple&& __in)
- noexcept(is_nothrow_move_assignable<_Inherited>::value)
+ operator=(typename conditional<__assignable<_T1, _T2>(),
+ tuple&&,
+ __nonesuch_no_braces&&>::type __in)
+ noexcept(__nothrow_assignable<_T1, _T2>())
{
static_cast<_Inherited&>(*this) = std::move(__in);
return *this;
}
template<typename _U1, typename _U2>
- tuple&
- operator=(const tuple<_U1, _U2>& __in)
- {
+ __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
+ operator=(const tuple<_U1, _U2>& __in)
+ noexcept(__nothrow_assignable<const _U1&, const _U2&>())
+ {
static_cast<_Inherited&>(*this) = __in;
return *this;
}
template<typename _U1, typename _U2>
- tuple&
- operator=(tuple<_U1, _U2>&& __in)
- {
+ __enable_if_t<__assignable<_U1, _U2>(), tuple&>
+ operator=(tuple<_U1, _U2>&& __in)
+ noexcept(__nothrow_assignable<_U1, _U2>())
+ {
static_cast<_Inherited&>(*this) = std::move(__in);
return *this;
}
template<typename _U1, typename _U2>
- tuple&
- operator=(const pair<_U1, _U2>& __in)
- {
+ __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
+ operator=(const pair<_U1, _U2>& __in)
+ noexcept(__nothrow_assignable<const _U1&, const _U2&>())
+ {
this->_M_head(*this) = __in.first;
this->_M_tail(*this)._M_head(*this) = __in.second;
return *this;
}
template<typename _U1, typename _U2>
- tuple&
- operator=(pair<_U1, _U2>&& __in)
- {
+ __enable_if_t<__assignable<_U1, _U2>(), tuple&>
+ operator=(pair<_U1, _U2>&& __in)
+ noexcept(__nothrow_assignable<_U1, _U2>())
+ {
this->_M_head(*this) = std::forward<_U1>(__in.first);
this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second);
return *this;
--- /dev/null
+// Copyright (C) 2018 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 <testsuite_tr1.h>
+
+using std::tuple;
+using std::pair;
+using __gnu_test::assign::AnyAssign;
+using __gnu_test::assign::DelAnyAssign;
+using __gnu_test::assign::DelCopyAssign;
+using __gnu_test::CopyConsOnlyType;
+
+// Copy assignment:
+template<typename T>
+constexpr bool copy() { return std::is_copy_assignable<T>::value; }
+
+// Move assigmment:
+template<typename T>
+constexpr bool move() { return std::is_move_assignable<T>::value; }
+
+static_assert( copy<tuple<>>(), "");
+static_assert( move<tuple<>>(), "");
+
+static_assert( copy<tuple<int>>(), "");
+static_assert( copy<tuple<AnyAssign>>(), "");
+static_assert( copy<tuple<int, int>>(), "");
+static_assert( copy<tuple<AnyAssign, AnyAssign>>(), "");
+static_assert( copy<tuple<int, AnyAssign>>(), "");
+static_assert( copy<tuple<AnyAssign, int>>(), "");
+static_assert( copy<tuple<int, int, int>>(), "");
+static_assert( copy<tuple<AnyAssign, AnyAssign, AnyAssign>>(), "");
+static_assert( copy<tuple<int, AnyAssign, AnyAssign>>(), "");
+static_assert( copy<tuple<AnyAssign, int, AnyAssign>>(), "");
+static_assert( copy<tuple<AnyAssign, AnyAssign, int>>(), "");
+
+static_assert( move<tuple<int>>(), "");
+static_assert( move<tuple<AnyAssign>>(), "");
+static_assert( move<tuple<int, int>>(), "");
+static_assert( move<tuple<AnyAssign, AnyAssign>>(), "");
+static_assert( move<tuple<int, AnyAssign>>(), "");
+static_assert( move<tuple<AnyAssign, int>>(), "");
+static_assert( move<tuple<int, int, int>>(), "");
+static_assert( move<tuple<AnyAssign, AnyAssign, AnyAssign>>(), "");
+static_assert( move<tuple<int, AnyAssign, AnyAssign>>(), "");
+static_assert( move<tuple<AnyAssign, int, AnyAssign>>(), "");
+static_assert( move<tuple<AnyAssign, AnyAssign, int>>(), "");
+
+static_assert( ! copy<tuple<DelCopyAssign>>(), "");
+static_assert( ! copy<tuple<DelCopyAssign, int>>(), "");
+static_assert( ! copy<tuple<int, DelCopyAssign>>(), "");
+static_assert( ! copy<tuple<DelCopyAssign, int, int>>(), "");
+static_assert( ! copy<tuple<int, DelCopyAssign, int>>(), "");
+static_assert( ! copy<tuple<int, int, DelCopyAssign>>(), "");
+
+static_assert( move<tuple<DelCopyAssign>>(), "");
+static_assert( move<tuple<DelCopyAssign, int>>(), "");
+static_assert( move<tuple<int, DelCopyAssign>>(), "");
+static_assert( move<tuple<DelCopyAssign, int, int>>(), "");
+static_assert( move<tuple<int, DelCopyAssign, int>>(), "");
+static_assert( move<tuple<int, int, DelCopyAssign>>(), "");
+
+static_assert( ! move<tuple<CopyConsOnlyType>>(), "");
+static_assert( ! move<tuple<CopyConsOnlyType, int>>(), "");
+static_assert( ! move<tuple<int, CopyConsOnlyType>>(), "");
+static_assert( ! move<tuple<CopyConsOnlyType, int, int>>(), "");
+static_assert( ! move<tuple<int, CopyConsOnlyType, int>>(), "");
+static_assert( ! move<tuple<int, int, CopyConsOnlyType>>(), "");
+
+// Assignment from different types of tuple (and pair):
+template<typename To, typename From>
+constexpr bool assign() { return std::is_assignable<To&, From>::value; }
+
+// 0-tuples
+static_assert( ! assign<tuple<>, tuple<int>>(), "" );
+static_assert( ! assign<tuple<>, const tuple<int>&>(), "" );
+
+// 1-tuples
+static_assert( ! assign<tuple<int>, tuple<>>(), "" );
+static_assert( ! assign<tuple<int>, const tuple<>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign>, tuple<>>(), "" );
+static_assert( ! assign<tuple<AnyAssign>, tuple<int, int>>(), "" );
+static_assert( ! assign<tuple<AnyAssign>, pair<int, int>>(), "" );
+
+static_assert( ! assign<tuple<void*>, tuple<int>>(), "" );
+static_assert( ! assign<tuple<void*>, const tuple<int>&>(), "" );
+
+static_assert( assign<tuple<long>, tuple<int>>(), "" );
+static_assert( assign<tuple<long>, tuple<int>&>(), "" );
+static_assert( assign<tuple<long>, const tuple<int>>(), "" );
+static_assert( assign<tuple<long>, const tuple<int>&>(), "" );
+
+// 2-tuples
+static_assert( assign<tuple<long, long>, tuple<int, int>>(), "" );
+static_assert( assign<tuple<long, long>, tuple<int, int>&>(), "" );
+static_assert( assign<tuple<long, long>, const tuple<int, int>>(), "" );
+static_assert( assign<tuple<long, long>, const tuple<int, int>&>(), "" );
+
+static_assert( assign<tuple<long, long>, pair<int, int>>(), "" );
+static_assert( assign<tuple<long, long>, const pair<int, int>&>(), "" );
+static_assert( assign<tuple<long, long>, pair<int, int>>(), "" );
+static_assert( assign<tuple<long, long>, const pair<int, int>&&>(), "" );
+
+static_assert( assign<tuple<DelCopyAssign, AnyAssign>,
+ tuple<DelCopyAssign, int>>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ tuple<DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ const tuple<DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ const tuple<DelCopyAssign, int>&&>(), "" );
+
+static_assert( assign<tuple<AnyAssign, DelCopyAssign>,
+ tuple<int, DelCopyAssign>>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ tuple<int, DelCopyAssign>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ const tuple<int, DelCopyAssign>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ const tuple<int, DelCopyAssign>&&>(), "" );
+
+static_assert( ! assign<tuple<void*, int>,
+ tuple<int, int>>(), "" );
+static_assert( ! assign<tuple<void*, int>,
+ const tuple<int, int>&>(), "" );
+
+static_assert( assign<tuple<DelCopyAssign, AnyAssign>,
+ pair<DelCopyAssign, int>>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ pair<DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ const pair<DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
+ const pair<DelCopyAssign, int>&&>(), "" );
+
+static_assert( assign<tuple<AnyAssign, DelCopyAssign>,
+ pair<int, DelCopyAssign>>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ pair<int, DelCopyAssign>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ const pair<int, DelCopyAssign>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
+ const pair<int, DelCopyAssign>&&>(), "" );
+
+static_assert( ! assign<tuple<void*, int>,
+ pair<int, int>>(), "" );
+static_assert( ! assign<tuple<void*, int>,
+ const pair<int, int>&>(), "" );
+
+// 3-tuples
+static_assert( assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
+ tuple<int, DelCopyAssign, int>>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
+ tuple<int, DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
+ const tuple<int, DelCopyAssign, int>&>(), "" );
+static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
+ const tuple<int, DelCopyAssign, int>&&>(), "" );
+
+static_assert( ! assign<tuple<int, void*, int>,
+ tuple<int, int, int>>(), "" );
+static_assert( ! assign<tuple<int, void*, int>,
+ const tuple<int, int, int>&>(), "" );