mirror of
https://github.com/llvm-mirror/libcxx.git
synced 2025-10-22 16:37:40 +08:00

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@287728 91177308-0d34-0410-b5e6-96231b3b80d8
175 lines
4.4 KiB
C++
175 lines
4.4 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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, c++11, c++14
|
|
|
|
// <variant>
|
|
|
|
// template <class ...Types> class variant;
|
|
|
|
// variant(variant&&) noexcept(see below);
|
|
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <variant>
|
|
|
|
#include "test_macros.h"
|
|
|
|
struct ThrowsMove {
|
|
ThrowsMove(ThrowsMove &&) noexcept(false) {}
|
|
};
|
|
|
|
struct NoCopy {
|
|
NoCopy(NoCopy const &) = delete;
|
|
};
|
|
|
|
struct MoveOnly {
|
|
int value;
|
|
MoveOnly(int v) : value(v) {}
|
|
MoveOnly(MoveOnly const &) = delete;
|
|
MoveOnly(MoveOnly &&) = default;
|
|
};
|
|
|
|
struct MoveOnlyNT {
|
|
int value;
|
|
MoveOnlyNT(int v) : value(v) {}
|
|
MoveOnlyNT(MoveOnlyNT const &) = delete;
|
|
MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; }
|
|
};
|
|
|
|
#ifndef TEST_HAS_NO_EXCEPTIONS
|
|
struct MakeEmptyT {
|
|
static int alive;
|
|
MakeEmptyT() { ++alive; }
|
|
MakeEmptyT(MakeEmptyT const &) {
|
|
++alive;
|
|
// Don't throw from the copy constructor since variant's assignment
|
|
// operator performs a copy before committing to the assignment.
|
|
}
|
|
MakeEmptyT(MakeEmptyT &&) { throw 42; }
|
|
MakeEmptyT &operator=(MakeEmptyT const &) { throw 42; }
|
|
MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
|
|
~MakeEmptyT() { --alive; }
|
|
};
|
|
|
|
int MakeEmptyT::alive = 0;
|
|
|
|
template <class Variant> void makeEmpty(Variant &v) {
|
|
Variant v2(std::in_place_type<MakeEmptyT>);
|
|
try {
|
|
v = v2;
|
|
assert(false);
|
|
} catch (...) {
|
|
assert(v.valueless_by_exception());
|
|
}
|
|
}
|
|
#endif // TEST_HAS_NO_EXCEPTIONS
|
|
|
|
void test_move_noexcept() {
|
|
{
|
|
using V = std::variant<int, long>;
|
|
static_assert(std::is_nothrow_move_constructible<V>::value, "");
|
|
}
|
|
{
|
|
using V = std::variant<int, MoveOnly>;
|
|
static_assert(std::is_nothrow_move_constructible<V>::value, "");
|
|
}
|
|
{
|
|
using V = std::variant<int, MoveOnlyNT>;
|
|
static_assert(!std::is_nothrow_move_constructible<V>::value, "");
|
|
}
|
|
{
|
|
using V = std::variant<int, ThrowsMove>;
|
|
static_assert(!std::is_nothrow_move_constructible<V>::value, "");
|
|
}
|
|
}
|
|
|
|
void test_move_ctor_sfinae() {
|
|
{
|
|
using V = std::variant<int, long>;
|
|
static_assert(std::is_move_constructible<V>::value, "");
|
|
}
|
|
{
|
|
using V = std::variant<int, MoveOnly>;
|
|
static_assert(std::is_move_constructible<V>::value, "");
|
|
}
|
|
{
|
|
using V = std::variant<int, MoveOnlyNT>;
|
|
static_assert(std::is_move_constructible<V>::value, "");
|
|
}
|
|
{
|
|
using V = std::variant<int, NoCopy>;
|
|
static_assert(!std::is_move_constructible<V>::value, "");
|
|
}
|
|
}
|
|
|
|
void test_move_ctor_basic() {
|
|
{
|
|
std::variant<int> v(std::in_place_index<0>, 42);
|
|
std::variant<int> v2 = std::move(v);
|
|
assert(v2.index() == 0);
|
|
assert(std::get<0>(v2) == 42);
|
|
}
|
|
{
|
|
std::variant<int, long> v(std::in_place_index<1>, 42);
|
|
std::variant<int, long> v2 = std::move(v);
|
|
assert(v2.index() == 1);
|
|
assert(std::get<1>(v2) == 42);
|
|
}
|
|
{
|
|
std::variant<MoveOnly> v(std::in_place_index<0>, 42);
|
|
assert(v.index() == 0);
|
|
std::variant<MoveOnly> v2(std::move(v));
|
|
assert(v2.index() == 0);
|
|
assert(std::get<0>(v2).value == 42);
|
|
}
|
|
{
|
|
std::variant<int, MoveOnly> v(std::in_place_index<1>, 42);
|
|
assert(v.index() == 1);
|
|
std::variant<int, MoveOnly> v2(std::move(v));
|
|
assert(v2.index() == 1);
|
|
assert(std::get<1>(v2).value == 42);
|
|
}
|
|
{
|
|
std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42);
|
|
assert(v.index() == 0);
|
|
std::variant<MoveOnlyNT> v2(std::move(v));
|
|
assert(v2.index() == 0);
|
|
assert(std::get<0>(v).value == -1);
|
|
assert(std::get<0>(v2).value == 42);
|
|
}
|
|
{
|
|
std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42);
|
|
assert(v.index() == 1);
|
|
std::variant<int, MoveOnlyNT> v2(std::move(v));
|
|
assert(v2.index() == 1);
|
|
assert(std::get<1>(v).value == -1);
|
|
assert(std::get<1>(v2).value == 42);
|
|
}
|
|
}
|
|
|
|
void test_move_ctor_valueless_by_exception() {
|
|
#ifndef TEST_HAS_NO_EXCEPTIONS
|
|
using V = std::variant<int, MakeEmptyT>;
|
|
V v1;
|
|
makeEmpty(v1);
|
|
V v(std::move(v1));
|
|
assert(v.valueless_by_exception());
|
|
#endif
|
|
}
|
|
|
|
int main() {
|
|
test_move_ctor_basic();
|
|
test_move_ctor_valueless_by_exception();
|
|
test_move_noexcept();
|
|
test_move_ctor_sfinae();
|
|
}
|