optional: Implement LWG 2900 and P0602
Differential Revision: https://reviews.llvm.org/D32385 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@307505 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
104
include/optional
104
include/optional
@@ -439,46 +439,122 @@ struct __optional_storage_base<_Tp, true>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class _Tp, bool = is_trivially_copyable<_Tp>::value>
|
template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
|
||||||
struct __optional_storage;
|
struct __optional_copy_base : __optional_storage_base<_Tp>
|
||||||
|
|
||||||
template <class _Tp>
|
|
||||||
struct __optional_storage<_Tp, true> : __optional_storage_base<_Tp>
|
|
||||||
{
|
{
|
||||||
using __optional_storage_base<_Tp>::__optional_storage_base;
|
using __optional_storage_base<_Tp>::__optional_storage_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
struct __optional_storage<_Tp, false> : __optional_storage_base<_Tp>
|
struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp>
|
||||||
{
|
{
|
||||||
using value_type = _Tp;
|
|
||||||
using __optional_storage_base<_Tp>::__optional_storage_base;
|
using __optional_storage_base<_Tp>::__optional_storage_base;
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
__optional_storage() = default;
|
__optional_copy_base() = default;
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
__optional_storage(const __optional_storage& __opt)
|
__optional_copy_base(const __optional_copy_base& __opt)
|
||||||
{
|
{
|
||||||
this->__construct_from(__opt);
|
this->__construct_from(__opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
__optional_storage(__optional_storage&& __opt)
|
__optional_copy_base(__optional_copy_base&&) = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_copy_base& operator=(const __optional_copy_base&) = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_copy_base& operator=(__optional_copy_base&&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Tp, bool = is_trivially_move_constructible<_Tp>::value>
|
||||||
|
struct __optional_move_base : __optional_copy_base<_Tp>
|
||||||
|
{
|
||||||
|
using __optional_copy_base<_Tp>::__optional_copy_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Tp>
|
||||||
|
struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp>
|
||||||
|
{
|
||||||
|
using value_type = _Tp;
|
||||||
|
using __optional_copy_base<_Tp>::__optional_copy_base;
|
||||||
|
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_base() = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_base(const __optional_move_base&) = default;
|
||||||
|
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_base(__optional_move_base&& __opt)
|
||||||
noexcept(is_nothrow_move_constructible_v<value_type>)
|
noexcept(is_nothrow_move_constructible_v<value_type>)
|
||||||
{
|
{
|
||||||
this->__construct_from(_VSTD::move(__opt));
|
this->__construct_from(_VSTD::move(__opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
__optional_storage& operator=(const __optional_storage& __opt)
|
__optional_move_base& operator=(const __optional_move_base&) = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_base& operator=(__optional_move_base&&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Tp, bool =
|
||||||
|
is_trivially_destructible<_Tp>::value &&
|
||||||
|
is_trivially_copy_constructible<_Tp>::value &&
|
||||||
|
is_trivially_copy_assignable<_Tp>::value>
|
||||||
|
struct __optional_copy_assign_base : __optional_move_base<_Tp>
|
||||||
|
{
|
||||||
|
using __optional_move_base<_Tp>::__optional_move_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Tp>
|
||||||
|
struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp>
|
||||||
|
{
|
||||||
|
using __optional_move_base<_Tp>::__optional_move_base;
|
||||||
|
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_copy_assign_base() = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_copy_assign_base(const __optional_copy_assign_base&) = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_copy_assign_base(__optional_copy_assign_base&&) = default;
|
||||||
|
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_copy_assign_base& operator=(const __optional_copy_assign_base& __opt)
|
||||||
{
|
{
|
||||||
this->__assign_from(__opt);
|
this->__assign_from(__opt);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
__optional_storage& operator=(__optional_storage&& __opt)
|
__optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Tp, bool =
|
||||||
|
is_trivially_destructible<_Tp>::value &&
|
||||||
|
is_trivially_move_constructible<_Tp>::value &&
|
||||||
|
is_trivially_move_assignable<_Tp>::value>
|
||||||
|
struct __optional_move_assign_base : __optional_copy_assign_base<_Tp>
|
||||||
|
{
|
||||||
|
using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Tp>
|
||||||
|
struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp>
|
||||||
|
{
|
||||||
|
using value_type = _Tp;
|
||||||
|
using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
|
||||||
|
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_assign_base() = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_assign_base(const __optional_move_assign_base& __opt) = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_assign_base(__optional_move_assign_base&&) = default;
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;
|
||||||
|
|
||||||
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
|
__optional_move_assign_base& operator=(__optional_move_assign_base&& __opt)
|
||||||
noexcept(is_nothrow_move_assignable_v<value_type> &&
|
noexcept(is_nothrow_move_assignable_v<value_type> &&
|
||||||
is_nothrow_move_constructible_v<value_type>)
|
is_nothrow_move_constructible_v<value_type>)
|
||||||
{
|
{
|
||||||
@@ -501,11 +577,11 @@ using __optional_sfinae_assign_base_t = __sfinae_assign_base<
|
|||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
class optional
|
class optional
|
||||||
: private __optional_storage<_Tp>
|
: private __optional_move_assign_base<_Tp>
|
||||||
, private __optional_sfinae_ctor_base_t<_Tp>
|
, private __optional_sfinae_ctor_base_t<_Tp>
|
||||||
, private __optional_sfinae_assign_base_t<_Tp>
|
, private __optional_sfinae_assign_base_t<_Tp>
|
||||||
{
|
{
|
||||||
using __base = __optional_storage<_Tp>;
|
using __base = __optional_move_assign_base<_Tp>;
|
||||||
public:
|
public:
|
||||||
using value_type = _Tp;
|
using value_type = _Tp;
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +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, c++11, c++14
|
|
||||||
// <optional>
|
|
||||||
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
#include "archetypes.hpp"
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct SpecialMemberTest {
|
|
||||||
using O = std::optional<T>;
|
|
||||||
|
|
||||||
template <template <class> class TestMF>
|
|
||||||
static constexpr bool check_same() {
|
|
||||||
return TestMF<O>::value == TestMF<T>::value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that optional inherits the correct trivial/non-trivial members
|
|
||||||
static_assert(check_same<std::is_trivially_destructible>(), "");
|
|
||||||
static_assert(check_same<std::is_trivially_copyable>(), "");
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class ...Args> static void sink(Args&&...) {}
|
|
||||||
|
|
||||||
template <class ...TestTypes>
|
|
||||||
struct DoTestsMetafunction {
|
|
||||||
DoTestsMetafunction() { sink(SpecialMemberTest<TestTypes>{}...); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TrivialMoveNonTrivialCopy {
|
|
||||||
TrivialMoveNonTrivialCopy() = default;
|
|
||||||
TrivialMoveNonTrivialCopy(const TrivialMoveNonTrivialCopy&) {}
|
|
||||||
TrivialMoveNonTrivialCopy(TrivialMoveNonTrivialCopy&&) = default;
|
|
||||||
TrivialMoveNonTrivialCopy& operator=(const TrivialMoveNonTrivialCopy&) { return *this; }
|
|
||||||
TrivialMoveNonTrivialCopy& operator=(TrivialMoveNonTrivialCopy&&) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TrivialCopyNonTrivialMove {
|
|
||||||
TrivialCopyNonTrivialMove() = default;
|
|
||||||
TrivialCopyNonTrivialMove(const TrivialCopyNonTrivialMove&) = default;
|
|
||||||
TrivialCopyNonTrivialMove(TrivialCopyNonTrivialMove&&) {}
|
|
||||||
TrivialCopyNonTrivialMove& operator=(const TrivialCopyNonTrivialMove&) = default;
|
|
||||||
TrivialCopyNonTrivialMove& operator=(TrivialCopyNonTrivialMove&&) { return *this; }
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
sink(
|
|
||||||
ImplicitTypes::ApplyTypes<DoTestsMetafunction>{},
|
|
||||||
ExplicitTypes::ApplyTypes<DoTestsMetafunction>{},
|
|
||||||
NonLiteralTypes::ApplyTypes<DoTestsMetafunction>{},
|
|
||||||
NonTrivialTypes::ApplyTypes<DoTestsMetafunction>{},
|
|
||||||
DoTestsMetafunction<TrivialMoveNonTrivialCopy, TrivialCopyNonTrivialMove>{}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -147,27 +147,27 @@ int main()
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
struct ThrowsMove {
|
struct ThrowsMove {
|
||||||
ThrowsMove() noexcept {}
|
ThrowsMove() noexcept {}
|
||||||
ThrowsMove(ThrowsMove const&) noexcept {}
|
ThrowsMove(ThrowsMove const&) noexcept {}
|
||||||
ThrowsMove(ThrowsMove &&) noexcept(false) {}
|
ThrowsMove(ThrowsMove &&) noexcept(false) {}
|
||||||
ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }
|
ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }
|
||||||
ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }
|
ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }
|
||||||
};
|
};
|
||||||
static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, "");
|
static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, "");
|
||||||
struct ThrowsMoveAssign {
|
struct ThrowsMoveAssign {
|
||||||
ThrowsMoveAssign() noexcept {}
|
ThrowsMoveAssign() noexcept {}
|
||||||
ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}
|
ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}
|
||||||
ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}
|
ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}
|
||||||
ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }
|
ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }
|
||||||
ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }
|
ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }
|
||||||
};
|
};
|
||||||
static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, "");
|
static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, "");
|
||||||
struct NoThrowMove {
|
struct NoThrowMove {
|
||||||
NoThrowMove() noexcept(false) {}
|
NoThrowMove() noexcept(false) {}
|
||||||
NoThrowMove(NoThrowMove const&) noexcept(false) {}
|
NoThrowMove(NoThrowMove const&) noexcept(false) {}
|
||||||
NoThrowMove(NoThrowMove &&) noexcept {}
|
NoThrowMove(NoThrowMove &&) noexcept {}
|
||||||
NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }
|
NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }
|
||||||
NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }
|
NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }
|
||||||
};
|
};
|
||||||
static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, "");
|
static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, "");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ constexpr bool constexpr_test(InitArgs&&... args)
|
|||||||
void test_throwing_ctor() {
|
void test_throwing_ctor() {
|
||||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||||
struct Z {
|
struct Z {
|
||||||
Z() : count(0) {}
|
Z() : count(0) {}
|
||||||
Z(Z const& o) : count(o.count + 1)
|
Z(Z const& o) : count(o.count + 1)
|
||||||
{ if (count == 2) throw 6; }
|
{ if (count == 2) throw 6; }
|
||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
const Z z;
|
const Z z;
|
||||||
const optional<Z> rhs(z);
|
const optional<Z> rhs(z);
|
||||||
|
|||||||
@@ -55,10 +55,10 @@ constexpr bool constexpr_test(InitArgs&&... args)
|
|||||||
void test_throwing_ctor() {
|
void test_throwing_ctor() {
|
||||||
#ifndef TEST_HAS_NO_EXCEPTIONS
|
#ifndef TEST_HAS_NO_EXCEPTIONS
|
||||||
struct Z {
|
struct Z {
|
||||||
Z() : count(0) {}
|
Z() : count(0) {}
|
||||||
Z(Z&& o) : count(o.count + 1)
|
Z(Z&& o) : count(o.count + 1)
|
||||||
{ if (count == 2) throw 6; }
|
{ if (count == 2) throw 6; }
|
||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
Z z;
|
Z z;
|
||||||
optional<Z> rhs(std::move(z));
|
optional<Z> rhs(std::move(z));
|
||||||
|
|||||||
@@ -33,10 +33,38 @@ struct SpecialMemberTest {
|
|||||||
"optional<T> is copy assignable if and only if T is both copy "
|
"optional<T> is copy assignable if and only if T is both copy "
|
||||||
"constructible and copy assignable.");
|
"constructible and copy assignable.");
|
||||||
static_assert(std::is_move_assignable_v<O> ==
|
static_assert(std::is_move_assignable_v<O> ==
|
||||||
((std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>) ||
|
((std::is_move_constructible_v<T> && std::is_move_assignable_v<T>) ||
|
||||||
(std::is_move_constructible_v<T> && std::is_move_assignable_v<T>)),
|
(std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>)),
|
||||||
"optional<T> is move assignable if and only if T is both move assignable and "
|
"optional<T> is move assignable if and only if T is both move constructible and "
|
||||||
"move constructible, or both copy constructible and copy assignable.");
|
"move assignable, or both copy constructible and copy assignable.");
|
||||||
|
|
||||||
|
// The following tests are for not-yet-standardized behavior (P0602):
|
||||||
|
static_assert(std::is_trivially_destructible_v<O> ==
|
||||||
|
std::is_trivially_destructible_v<T>,
|
||||||
|
"optional<T> is trivially destructible if and only if T is.");
|
||||||
|
static_assert(std::is_trivially_copy_constructible_v<O> ==
|
||||||
|
std::is_trivially_copy_constructible_v<T>,
|
||||||
|
"optional<T> is trivially copy constructible if and only if T is.");
|
||||||
|
static_assert(std::is_trivially_move_constructible_v<O> ==
|
||||||
|
std::is_trivially_move_constructible_v<T> ||
|
||||||
|
(!std::is_move_constructible_v<T> && std::is_trivially_copy_constructible_v<T>),
|
||||||
|
"optional<T> is trivially move constructible if T is trivially move constructible, "
|
||||||
|
"or if T is trivially copy constructible and is not move constructible.");
|
||||||
|
static_assert(std::is_trivially_copy_assignable_v<O> ==
|
||||||
|
(std::is_trivially_destructible_v<T> &&
|
||||||
|
std::is_trivially_copy_constructible_v<T> &&
|
||||||
|
std::is_trivially_copy_assignable_v<T>),
|
||||||
|
"optional<T> is trivially copy assignable if and only if T is trivially destructible, "
|
||||||
|
"trivially copy constructible, and trivially copy assignable.");
|
||||||
|
static_assert(std::is_trivially_move_assignable_v<O> ==
|
||||||
|
(std::is_trivially_destructible_v<T> &&
|
||||||
|
((std::is_trivially_move_constructible_v<T> && std::is_trivially_move_assignable_v<T>) ||
|
||||||
|
((!std::is_move_constructible_v<T> || !std::is_move_assignable_v<T>) &&
|
||||||
|
std::is_trivially_copy_constructible_v<T> && std::is_trivially_copy_assignable_v<T>))),
|
||||||
|
"optional<T> is trivially move assignable if T is trivially destructible, and either "
|
||||||
|
"(1) trivially move constructible and trivially move assignable, or "
|
||||||
|
"(2) not move constructible or not move assignable, and "
|
||||||
|
"trivially copy constructible and trivially copy assignable.");
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ...Args> static void sink(Args&&...) {}
|
template <class ...Args> static void sink(Args&&...) {}
|
||||||
|
|||||||
Reference in New Issue
Block a user