//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03 // // template struct pair // pair& operator=(pair&& p); #include #include #include #include "test_macros.h" #include "archetypes.h" struct CountAssign { int copied = 0; int moved = 0; TEST_CONSTEXPR_CXX20 CountAssign() = default; TEST_CONSTEXPR_CXX20 CountAssign& operator=(CountAssign const&) { ++copied; return *this; } TEST_CONSTEXPR_CXX20 CountAssign& operator=(CountAssign&&) { ++moved; return *this; } }; struct NotAssignable { NotAssignable& operator=(NotAssignable const&) = delete; NotAssignable& operator=(NotAssignable&&) = delete; }; struct MoveAssignable { MoveAssignable& operator=(MoveAssignable const&) = delete; MoveAssignable& operator=(MoveAssignable&&) = default; }; struct CopyAssignable { CopyAssignable& operator=(CopyAssignable const&) = default; CopyAssignable& operator=(CopyAssignable&&) = delete; }; TEST_CONSTEXPR_CXX20 bool test() { { typedef std::pair P; P p1(3, 4); P p2; p2 = std::move(p1); assert(p2.first.value == 3); assert(p2.second == 4); } { using P = std::pair; 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; static_assert(!std::is_move_assignable

::value, ""); } { // The move decays to the copy constructor using P = std::pair; static_assert(std::is_move_assignable

::value, ""); P p; P p2; p = std::move(p2); assert(p.first.moved == 0); assert(p.first.copied == 1); assert(p2.first.moved == 0); assert(p2.first.copied == 0); } { using P = std::pair; static_assert(std::is_move_assignable

::value, ""); P p; P p2; p = std::move(p2); assert(p.first.moved == 1); assert(p.first.copied == 0); assert(p2.first.moved == 0); assert(p2.first.copied == 0); } { using P1 = std::pair; using P2 = std::pair; using P3 = std::pair; static_assert(!std::is_move_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); } { // We assign through the reference and don't move out of the incoming ref, // so this doesn't work (but would if the type were CopyAssignable). using P1 = std::pair; static_assert(!std::is_move_assignable::value, ""); // ... works if it's CopyAssignable using P2 = std::pair; static_assert(std::is_move_assignable::value, ""); // For rvalue-references, we can move-assign if the type is MoveAssignable // or CopyAssignable (since in the worst case the move will decay into a copy). using P3 = std::pair; using P4 = std::pair; static_assert(std::is_move_assignable::value, ""); static_assert(std::is_move_assignable::value, ""); // In all cases, we can't move-assign if the types are not assignable, // since we assign through the reference. using P5 = std::pair; using P6 = std::pair; static_assert(!std::is_move_assignable::value, ""); static_assert(!std::is_move_assignable::value, ""); } return true; } int main(int, char**) { test(); #if TEST_STD_VER >= 20 static_assert(test()); #endif return 0; }