Revert r276548 - Make pair/tuples assignment operators SFINAE properly.
This is a breaking change. The SFINAE required is instantiated the second the class is instantiated, and this can cause hard SFINAE errors when applied to references to incomplete types. Ex. struct IncompleteType; extern IncompleteType it; std::tuple<IncompleteType&> t(it); // SFINAE will blow up. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@276598 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -647,9 +647,6 @@ public:
|
|||||||
_LIBCPP_CONSTEXPR tuple()
|
_LIBCPP_CONSTEXPR tuple()
|
||||||
_NOEXCEPT_(__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
|
_NOEXCEPT_(__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
|
||||||
|
|
||||||
tuple(tuple const&) = default;
|
|
||||||
tuple(tuple&&) = default;
|
|
||||||
|
|
||||||
template <class _AllocArgT, class _Alloc, bool _Dummy = true, class = typename enable_if<
|
template <class _AllocArgT, class _Alloc, bool _Dummy = true, class = typename enable_if<
|
||||||
__lazy_and<
|
__lazy_and<
|
||||||
is_same<allocator_arg_t, _AllocArgT>,
|
is_same<allocator_arg_t, _AllocArgT>,
|
||||||
@@ -888,25 +885,6 @@ public:
|
|||||||
tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
|
tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
|
||||||
: base_(allocator_arg_t(), __a, _VSTD::forward<_Tuple>(__t)) {}
|
: base_(allocator_arg_t(), __a, _VSTD::forward<_Tuple>(__t)) {}
|
||||||
|
|
||||||
using _CanCopyAssign = __all<is_copy_assignable<_Tp>::value...>;
|
|
||||||
using _CanMoveAssign = __all<is_move_assignable<_Tp>::value...>;
|
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
|
||||||
tuple& operator=(typename conditional<_CanCopyAssign::value, tuple, __nat>::type const& __t)
|
|
||||||
_NOEXCEPT_((__all<is_nothrow_copy_assignable<_Tp>::value...>::value))
|
|
||||||
{
|
|
||||||
base_.operator=(__t.base_);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
|
||||||
tuple& operator=(typename conditional<_CanMoveAssign::value, tuple, __nat>::type&& __t)
|
|
||||||
_NOEXCEPT_((__all<is_nothrow_move_assignable<_Tp>::value...>::value))
|
|
||||||
{
|
|
||||||
base_.operator=(static_cast<base&&>(__t.base_));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class _Tuple,
|
template <class _Tuple,
|
||||||
class = typename enable_if
|
class = typename enable_if
|
||||||
<
|
<
|
||||||
|
|||||||
@@ -348,19 +348,8 @@ struct _LIBCPP_TYPE_VIS_ONLY pair
|
|||||||
// Use the implicitly declared copy constructor in C++03
|
// Use the implicitly declared copy constructor in C++03
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef typename remove_reference<_T1>::type _T1Unref;
|
|
||||||
typedef typename remove_reference<_T2>::type _T2Unref;
|
|
||||||
|
|
||||||
#if !defined(_LIBCPP_CXX03_LANG)
|
|
||||||
typedef integral_constant<bool,
|
|
||||||
is_copy_assignable<_T1>::value
|
|
||||||
&& is_copy_assignable<_T2>::value> _CanCopyAssign;
|
|
||||||
#else
|
|
||||||
typedef true_type _CanCopyAssign;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
pair& operator=(typename conditional<_CanCopyAssign::value, pair, __nat>::type const& __p)
|
pair& operator=(const pair& __p)
|
||||||
_NOEXCEPT_(is_nothrow_copy_assignable<first_type>::value &&
|
_NOEXCEPT_(is_nothrow_copy_assignable<first_type>::value &&
|
||||||
is_nothrow_copy_assignable<second_type>::value)
|
is_nothrow_copy_assignable<second_type>::value)
|
||||||
{
|
{
|
||||||
@@ -388,15 +377,10 @@ struct _LIBCPP_TYPE_VIS_ONLY pair
|
|||||||
: first(_VSTD::forward<_U1>(__p.first)),
|
: first(_VSTD::forward<_U1>(__p.first)),
|
||||||
second(_VSTD::forward<_U2>(__p.second)) {}
|
second(_VSTD::forward<_U2>(__p.second)) {}
|
||||||
|
|
||||||
typedef integral_constant<bool,
|
|
||||||
is_move_assignable<_T1>::value
|
|
||||||
&& is_move_assignable<_T2>::value> _CanMoveAssign;
|
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
pair&
|
pair&
|
||||||
operator=(typename conditional<_CanMoveAssign::value, pair, __nat>::type&& __p)
|
operator=(pair&& __p) _NOEXCEPT_(is_nothrow_move_assignable<first_type>::value &&
|
||||||
_NOEXCEPT_(is_nothrow_move_assignable<first_type>::value &&
|
is_nothrow_move_assignable<second_type>::value)
|
||||||
is_nothrow_move_assignable<second_type>::value)
|
|
||||||
{
|
{
|
||||||
first = _VSTD::forward<first_type>(__p.first);
|
first = _VSTD::forward<first_type>(__p.first);
|
||||||
second = _VSTD::forward<second_type>(__p.second);
|
second = _VSTD::forward<second_type>(__p.second);
|
||||||
@@ -404,6 +388,7 @@ struct _LIBCPP_TYPE_VIS_ONLY pair
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _LIBCPP_HAS_NO_VARIADICS
|
#ifndef _LIBCPP_HAS_NO_VARIADICS
|
||||||
|
|
||||||
template<class _Tuple,
|
template<class _Tuple,
|
||||||
class = typename enable_if<__tuple_convertible<_Tuple, pair>::value>::type>
|
class = typename enable_if<__tuple_convertible<_Tuple, pair>::value>::type>
|
||||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
|
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
|
||||||
@@ -426,7 +411,7 @@ struct _LIBCPP_TYPE_VIS_ONLY pair
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
template <class _Tuple,
|
template <class _Tuple,
|
||||||
class = typename enable_if<!is_same<typename decay<_Tuple>::type, pair>::value && __tuple_assignable<_Tuple, pair>::value>::type>
|
class = typename enable_if<__tuple_assignable<_Tuple, pair>::value>::type>
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
pair&
|
pair&
|
||||||
operator=(_Tuple&& __p)
|
operator=(_Tuple&& __p)
|
||||||
|
|||||||
@@ -19,22 +19,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "test_macros.h"
|
|
||||||
|
|
||||||
struct NonAssignable {
|
|
||||||
NonAssignable& operator=(NonAssignable const&) = delete;
|
|
||||||
NonAssignable& operator=(NonAssignable&&) = delete;
|
|
||||||
};
|
|
||||||
struct CopyAssignable {
|
|
||||||
CopyAssignable& operator=(CopyAssignable const&) = default;
|
|
||||||
CopyAssignable& operator=(CopyAssignable &&) = delete;
|
|
||||||
};
|
|
||||||
static_assert(std::is_copy_assignable<CopyAssignable>::value, "");
|
|
||||||
struct MoveAssignable {
|
|
||||||
MoveAssignable& operator=(MoveAssignable const&) = delete;
|
|
||||||
MoveAssignable& operator=(MoveAssignable&&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -67,37 +51,4 @@ int main()
|
|||||||
assert(std::get<1>(t) == 'a');
|
assert(std::get<1>(t) == 'a');
|
||||||
assert(std::get<2>(t) == "some text");
|
assert(std::get<2>(t) == "some text");
|
||||||
}
|
}
|
||||||
{
|
|
||||||
// test reference assignment.
|
|
||||||
using T = std::tuple<int&, int&&>;
|
|
||||||
int x = 42;
|
|
||||||
int y = 100;
|
|
||||||
int x2 = -1;
|
|
||||||
int y2 = 500;
|
|
||||||
T t(x, std::move(y));
|
|
||||||
T t2(x2, std::move(y2));
|
|
||||||
t = t2;
|
|
||||||
assert(std::get<0>(t) == x2);
|
|
||||||
assert(&std::get<0>(t) == &x);
|
|
||||||
assert(std::get<1>(t) == y2);
|
|
||||||
assert(&std::get<1>(t) == &y);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// test that the implicitly generated copy assignment operator
|
|
||||||
// is properly deleted
|
|
||||||
using T = std::tuple<std::unique_ptr<int>>;
|
|
||||||
static_assert(!std::is_copy_assignable<T>::value, "");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using T = std::tuple<int, NonAssignable>;
|
|
||||||
static_assert(!std::is_copy_assignable<T>::value, "");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using T = std::tuple<int, CopyAssignable>;
|
|
||||||
static_assert(std::is_copy_assignable<T>::value, "");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using T = std::tuple<int, MoveAssignable>;
|
|
||||||
static_assert(!std::is_copy_assignable<T>::value, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,33 +21,6 @@
|
|||||||
|
|
||||||
#include "MoveOnly.h"
|
#include "MoveOnly.h"
|
||||||
|
|
||||||
struct NonAssignable {
|
|
||||||
NonAssignable& operator=(NonAssignable const&) = delete;
|
|
||||||
NonAssignable& operator=(NonAssignable&&) = delete;
|
|
||||||
};
|
|
||||||
struct CopyAssignable {
|
|
||||||
CopyAssignable& operator=(CopyAssignable const&) = default;
|
|
||||||
CopyAssignable& operator=(CopyAssignable&&) = delete;
|
|
||||||
};
|
|
||||||
static_assert(std::is_copy_assignable<CopyAssignable>::value, "");
|
|
||||||
struct MoveAssignable {
|
|
||||||
MoveAssignable& operator=(MoveAssignable const&) = delete;
|
|
||||||
MoveAssignable& operator=(MoveAssignable&&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct CountAssign {
|
|
||||||
static int copied;
|
|
||||||
static int moved;
|
|
||||||
static void reset() { copied = moved = 0; }
|
|
||||||
CountAssign() = default;
|
|
||||||
CountAssign& operator=(CountAssign const&) { ++copied; return *this; }
|
|
||||||
CountAssign& operator=(CountAssign&&) { ++moved; return *this; }
|
|
||||||
};
|
|
||||||
int CountAssign::copied = 0;
|
|
||||||
int CountAssign::moved = 0;
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -80,46 +53,4 @@ int main()
|
|||||||
assert(std::get<1>(t) == 1);
|
assert(std::get<1>(t) == 1);
|
||||||
assert(std::get<2>(t) == 2);
|
assert(std::get<2>(t) == 2);
|
||||||
}
|
}
|
||||||
{
|
|
||||||
// test reference assignment.
|
|
||||||
using T = std::tuple<int&, int&&>;
|
|
||||||
int x = 42;
|
|
||||||
int y = 100;
|
|
||||||
int x2 = -1;
|
|
||||||
int y2 = 500;
|
|
||||||
T t(x, std::move(y));
|
|
||||||
T t2(x2, std::move(y2));
|
|
||||||
t = std::move(t2);
|
|
||||||
assert(std::get<0>(t) == x2);
|
|
||||||
assert(&std::get<0>(t) == &x);
|
|
||||||
assert(std::get<1>(t) == y2);
|
|
||||||
assert(&std::get<1>(t) == &y);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// test that the implicitly generated move assignment operator
|
|
||||||
// is properly deleted
|
|
||||||
using T = std::tuple<std::unique_ptr<int>>;
|
|
||||||
static_assert(std::is_move_assignable<T>::value, "");
|
|
||||||
static_assert(!std::is_copy_assignable<T>::value, "");
|
|
||||||
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using T = std::tuple<int, NonAssignable>;
|
|
||||||
static_assert(!std::is_move_assignable<T>::value, "");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using T = std::tuple<int, MoveAssignable>;
|
|
||||||
static_assert(std::is_move_assignable<T>::value, "");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// The move should decay to a copy.
|
|
||||||
CountAssign::reset();
|
|
||||||
using T = std::tuple<CountAssign, CopyAssignable>;
|
|
||||||
static_assert(std::is_move_assignable<T>::value, "");
|
|
||||||
T t1;
|
|
||||||
T t2;
|
|
||||||
t1 = std::move(t2);
|
|
||||||
assert(CountAssign::copied == 1);
|
|
||||||
assert(CountAssign::moved == 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
|
||||||
// Source Licenses. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// UNSUPPORTED: c++98, c++03
|
|
||||||
|
|
||||||
// <utility>
|
|
||||||
|
|
||||||
// template <class T1, class T2> struct pair
|
|
||||||
|
|
||||||
// pair& operator=(pair const& p);
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
|
|
||||||
struct NonAssignable {
|
|
||||||
NonAssignable& operator=(NonAssignable const&) = delete;
|
|
||||||
NonAssignable& operator=(NonAssignable&&) = delete;
|
|
||||||
};
|
|
||||||
struct CopyAssignable {
|
|
||||||
CopyAssignable() = default;
|
|
||||||
CopyAssignable(CopyAssignable const&) = default;
|
|
||||||
CopyAssignable& operator=(CopyAssignable const&) = default;
|
|
||||||
CopyAssignable& operator=(CopyAssignable&&) = delete;
|
|
||||||
};
|
|
||||||
struct MoveAssignable {
|
|
||||||
MoveAssignable() = default;
|
|
||||||
MoveAssignable& operator=(MoveAssignable const&) = delete;
|
|
||||||
MoveAssignable& operator=(MoveAssignable&&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct CountAssign {
|
|
||||||
static int copied;
|
|
||||||
static int moved;
|
|
||||||
static void reset() { copied = moved = 0; }
|
|
||||||
CountAssign() = default;
|
|
||||||
CountAssign& operator=(CountAssign const&) { ++copied; return *this; }
|
|
||||||
CountAssign& operator=(CountAssign&&) { ++moved; return *this; }
|
|
||||||
};
|
|
||||||
int CountAssign::copied = 0;
|
|
||||||
int CountAssign::moved = 0;
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
{
|
|
||||||
typedef std::pair<CopyAssignable, short> P;
|
|
||||||
const P p1(CopyAssignable(), 4);
|
|
||||||
P p2;
|
|
||||||
p2 = p1;
|
|
||||||
assert(p2.second == 4);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using P = std::pair<int&, int&&>;
|
|
||||||
int x = 42;
|
|
||||||
int y = 101;
|
|
||||||
int x2 = -1;
|
|
||||||
int y2 = 300;
|
|
||||||
P p1(x, std::move(y));
|
|
||||||
P p2(x2, std::move(y2));
|
|
||||||
p1 = p2;
|
|
||||||
assert(p1.first == x2);
|
|
||||||
assert(p1.second == y2);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using P = std::pair<int, NonAssignable>;
|
|
||||||
static_assert(!std::is_copy_assignable<P>::value, "");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CountAssign::reset();
|
|
||||||
using P = std::pair<CountAssign, CopyAssignable>;
|
|
||||||
static_assert(std::is_copy_assignable<P>::value, "");
|
|
||||||
P p;
|
|
||||||
P p2;
|
|
||||||
p = p2;
|
|
||||||
assert(CountAssign::copied == 1);
|
|
||||||
assert(CountAssign::moved == 0);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using P = std::pair<int, MoveAssignable>;
|
|
||||||
static_assert(!std::is_copy_assignable<P>::value, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
|
||||||
// Source Licenses. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// REQUIRES-ANY: c++98, c++03
|
|
||||||
|
|
||||||
// <utility>
|
|
||||||
|
|
||||||
// template <class T1, class T2> struct pair
|
|
||||||
|
|
||||||
// pair& operator=(pair const& p);
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
|
|
||||||
struct NonAssignable {
|
|
||||||
NonAssignable() {}
|
|
||||||
private:
|
|
||||||
NonAssignable& operator=(NonAssignable const&);
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// Test that we don't constrain the assignment operator in C++03 mode.
|
|
||||||
// Since we don't have access control SFINAE having pair evaluate SFINAE
|
|
||||||
// may cause a hard error.
|
|
||||||
typedef std::pair<int, NonAssignable> P;
|
|
||||||
static_assert(std::is_copy_assignable<P>::value, "");
|
|
||||||
}
|
|
||||||
@@ -7,8 +7,6 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
// UNSUPPORTED: c++98, c++03
|
|
||||||
|
|
||||||
// <utility>
|
// <utility>
|
||||||
|
|
||||||
// template <class T1, class T2> struct pair
|
// template <class T1, class T2> struct pair
|
||||||
@@ -19,35 +17,9 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
struct NonAssignable {
|
|
||||||
NonAssignable& operator=(NonAssignable const&) = delete;
|
|
||||||
NonAssignable& operator=(NonAssignable&&) = delete;
|
|
||||||
};
|
|
||||||
struct CopyAssignable {
|
|
||||||
CopyAssignable() = default;
|
|
||||||
CopyAssignable& operator=(CopyAssignable const&) = default;
|
|
||||||
CopyAssignable& operator=(CopyAssignable&&) = delete;
|
|
||||||
};
|
|
||||||
struct MoveAssignable {
|
|
||||||
MoveAssignable() = default;
|
|
||||||
MoveAssignable& operator=(MoveAssignable const&) = delete;
|
|
||||||
MoveAssignable& operator=(MoveAssignable&&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CountAssign {
|
|
||||||
static int copied;
|
|
||||||
static int moved;
|
|
||||||
static void reset() { copied = moved = 0; }
|
|
||||||
CountAssign() = default;
|
|
||||||
CountAssign& operator=(CountAssign const&) { ++copied; return *this; }
|
|
||||||
CountAssign& operator=(CountAssign&&) { ++moved; return *this; }
|
|
||||||
};
|
|
||||||
int CountAssign::copied = 0;
|
|
||||||
int CountAssign::moved = 0;
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||||
{
|
{
|
||||||
typedef std::pair<std::unique_ptr<int>, short> P;
|
typedef std::pair<std::unique_ptr<int>, short> P;
|
||||||
P p1(std::unique_ptr<int>(new int(3)), 4);
|
P p1(std::unique_ptr<int>(new int(3)), 4);
|
||||||
@@ -56,41 +28,5 @@ int main()
|
|||||||
assert(*p2.first == 3);
|
assert(*p2.first == 3);
|
||||||
assert(p2.second == 4);
|
assert(p2.second == 4);
|
||||||
}
|
}
|
||||||
{
|
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||||
using P = std::pair<int&, int&&>;
|
|
||||||
int x = 42;
|
|
||||||
int y = 101;
|
|
||||||
int x2 = -1;
|
|
||||||
int y2 = 300;
|
|
||||||
P p1(x, std::move(y));
|
|
||||||
P p2(x2, std::move(y2));
|
|
||||||
p1 = std::move(p2);
|
|
||||||
assert(p1.first == x2);
|
|
||||||
assert(p1.second == y2);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using P = std::pair<int, NonAssignable>;
|
|
||||||
static_assert(!std::is_move_assignable<P>::value, "");
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// The move decays to the copy constructor
|
|
||||||
CountAssign::reset();
|
|
||||||
using P = std::pair<CountAssign, CopyAssignable>;
|
|
||||||
static_assert(std::is_move_assignable<P>::value, "");
|
|
||||||
P p;
|
|
||||||
P p2;
|
|
||||||
p = std::move(p2);
|
|
||||||
assert(CountAssign::moved == 0);
|
|
||||||
assert(CountAssign::copied == 1);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
CountAssign::reset();
|
|
||||||
using P = std::pair<CountAssign, MoveAssignable>;
|
|
||||||
static_assert(std::is_move_assignable<P>::value, "");
|
|
||||||
P p;
|
|
||||||
P p2;
|
|
||||||
p = std::move(p2);
|
|
||||||
assert(CountAssign::moved == 1);
|
|
||||||
assert(CountAssign::copied == 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user