re PR libstdc++/80187 (C++ variant should be trivially copy constructible if possible)
PR libstdc++/80187 * include/std/variant (variant::variant, variant::~variant, variant::operator=): Implement triviality forwarding for four special member functions. * testsuite/20_util/variant/compile.cc: Tests. From-SVN: r249706
This commit is contained in:
parent
8c2805bbbb
commit
7050372474
3 changed files with 341 additions and 82 deletions
|
@ -1,3 +1,11 @@
|
|||
2017-06-27 Tim Shen <timshen@google.com>
|
||||
|
||||
PR libstdc++/80187
|
||||
* include/std/variant (variant::variant, variant::~variant,
|
||||
variant::operator=): Implement triviality forwarding for four
|
||||
special member functions.
|
||||
* testsuite/20_util/variant/compile.cc: Tests.
|
||||
|
||||
2017-06-27 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/81221
|
||||
|
|
|
@ -295,6 +295,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__variant::__ref_cast<_Tp>(__t));
|
||||
}
|
||||
|
||||
template<typename... _Types>
|
||||
struct _Traits
|
||||
{
|
||||
static constexpr bool _S_default_ctor =
|
||||
is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
|
||||
static constexpr bool _S_copy_ctor =
|
||||
(is_copy_constructible_v<_Types> && ...);
|
||||
static constexpr bool _S_move_ctor =
|
||||
(is_move_constructible_v<_Types> && ...);
|
||||
static constexpr bool _S_copy_assign =
|
||||
_S_copy_ctor && _S_move_ctor
|
||||
&& (is_copy_assignable_v<_Types> && ...);
|
||||
static constexpr bool _S_move_assign =
|
||||
_S_move_ctor
|
||||
&& (is_move_assignable_v<_Types> && ...);
|
||||
|
||||
static constexpr bool _S_trivial_dtor =
|
||||
(is_trivially_destructible_v<_Types> && ...);
|
||||
static constexpr bool _S_trivial_copy_ctor =
|
||||
(is_trivially_copy_constructible_v<_Types> && ...);
|
||||
static constexpr bool _S_trivial_move_ctor =
|
||||
(is_trivially_move_constructible_v<_Types> && ...);
|
||||
static constexpr bool _S_trivial_copy_assign =
|
||||
_S_trivial_dtor && (is_trivially_copy_assignable_v<_Types> && ...);
|
||||
static constexpr bool _S_trivial_move_assign =
|
||||
_S_trivial_dtor && (is_trivially_move_assignable_v<_Types> && ...);
|
||||
|
||||
// The following nothrow traits are for non-trivial SMFs. Trivial SMFs
|
||||
// are always nothrow.
|
||||
static constexpr bool _S_nothrow_default_ctor =
|
||||
is_nothrow_default_constructible_v<
|
||||
typename _Nth_type<0, _Types...>::type>;
|
||||
static constexpr bool _S_nothrow_copy_ctor = false;
|
||||
static constexpr bool _S_nothrow_move_ctor =
|
||||
(is_nothrow_move_constructible_v<_Types> && ...);
|
||||
static constexpr bool _S_nothrow_copy_assign = false;
|
||||
static constexpr bool _S_nothrow_move_assign =
|
||||
_S_nothrow_move_ctor && (is_nothrow_move_assignable_v<_Types> && ...);
|
||||
};
|
||||
|
||||
// Defines members and ctors.
|
||||
template<typename... _Types>
|
||||
union _Variadic_union { };
|
||||
|
@ -360,6 +400,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
~_Variant_storage()
|
||||
{ _M_reset(); }
|
||||
|
||||
void*
|
||||
_M_storage() const
|
||||
{
|
||||
return const_cast<void*>(static_cast<const void*>(
|
||||
std::addressof(_M_u)));
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
_M_valid() const noexcept
|
||||
{
|
||||
return this->_M_index != __index_type(variant_npos);
|
||||
}
|
||||
|
||||
_Variadic_union<_Types...> _M_u;
|
||||
using __index_type = __select_index<_Types...>;
|
||||
__index_type _M_index;
|
||||
|
@ -379,59 +432,108 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
void _M_reset()
|
||||
{ _M_index = variant_npos; }
|
||||
|
||||
void*
|
||||
_M_storage() const
|
||||
{
|
||||
return const_cast<void*>(static_cast<const void*>(
|
||||
std::addressof(_M_u)));
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
_M_valid() const noexcept
|
||||
{
|
||||
return this->_M_index != __index_type(variant_npos);
|
||||
}
|
||||
|
||||
_Variadic_union<_Types...> _M_u;
|
||||
using __index_type = __select_index<_Types...>;
|
||||
__index_type _M_index;
|
||||
};
|
||||
|
||||
// Helps SFINAE on special member functions. Otherwise it can live in variant
|
||||
// class.
|
||||
template<typename... _Types>
|
||||
struct _Variant_base :
|
||||
_Variant_storage<(std::is_trivially_destructible_v<_Types> && ...),
|
||||
_Types...>
|
||||
using _Variant_storage_alias =
|
||||
_Variant_storage<_Traits<_Types...>::_S_trivial_dtor, _Types...>;
|
||||
|
||||
// The following are (Copy|Move) (ctor|assign) layers for forwarding
|
||||
// triviality and handling non-trivial SMF behaviors.
|
||||
|
||||
template<bool, typename... _Types>
|
||||
struct _Copy_ctor_base : _Variant_storage_alias<_Types...>
|
||||
{
|
||||
using _Storage =
|
||||
_Variant_storage<(std::is_trivially_destructible_v<_Types> && ...),
|
||||
_Types...>;
|
||||
using _Base = _Variant_storage_alias<_Types...>;
|
||||
using _Base::_Base;
|
||||
|
||||
constexpr
|
||||
_Variant_base()
|
||||
noexcept(is_nothrow_default_constructible_v<
|
||||
variant_alternative_t<0, variant<_Types...>>>)
|
||||
: _Variant_base(in_place_index<0>) { }
|
||||
|
||||
_Variant_base(const _Variant_base& __rhs)
|
||||
_Copy_ctor_base(const _Copy_ctor_base& __rhs)
|
||||
noexcept(_Traits<_Types...>::_S_nothrow_copy_ctor)
|
||||
{
|
||||
if (__rhs._M_valid())
|
||||
{
|
||||
static constexpr void (*_S_vtable[])(void*, void*) =
|
||||
{ &__erased_ctor<_Types&, const _Types&>... };
|
||||
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
|
||||
_S_vtable[__rhs._M_index](this->_M_storage(), __rhs._M_storage());
|
||||
this->_M_index = __rhs._M_index;
|
||||
}
|
||||
}
|
||||
|
||||
_Variant_base(_Variant_base&& __rhs)
|
||||
noexcept((is_nothrow_move_constructible_v<_Types> && ...))
|
||||
_Copy_ctor_base(_Copy_ctor_base&&) = default;
|
||||
_Copy_ctor_base& operator=(const _Copy_ctor_base&) = default;
|
||||
_Copy_ctor_base& operator=(_Copy_ctor_base&&) = default;
|
||||
};
|
||||
|
||||
template<typename... _Types>
|
||||
struct _Copy_ctor_base<true, _Types...> : _Variant_storage_alias<_Types...>
|
||||
{
|
||||
using _Base = _Variant_storage_alias<_Types...>;
|
||||
using _Base::_Base;
|
||||
};
|
||||
|
||||
template<typename... _Types>
|
||||
using _Copy_ctor_alias =
|
||||
_Copy_ctor_base<_Traits<_Types...>::_S_trivial_copy_ctor, _Types...>;
|
||||
|
||||
template<bool, typename... _Types>
|
||||
struct _Move_ctor_base : _Copy_ctor_alias<_Types...>
|
||||
{
|
||||
using _Base = _Copy_ctor_alias<_Types...>;
|
||||
using _Base::_Base;
|
||||
|
||||
_Move_ctor_base(_Move_ctor_base&& __rhs)
|
||||
noexcept(_Traits<_Types...>::_S_nothrow_move_ctor)
|
||||
{
|
||||
if (__rhs._M_valid())
|
||||
{
|
||||
static constexpr void (*_S_vtable[])(void*, void*) =
|
||||
{ &__erased_ctor<_Types&, _Types&&>... };
|
||||
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
|
||||
_S_vtable[__rhs._M_index](this->_M_storage(), __rhs._M_storage());
|
||||
this->_M_index = __rhs._M_index;
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t _Np, typename... _Args>
|
||||
constexpr explicit
|
||||
_Variant_base(in_place_index_t<_Np> __i, _Args&&... __args)
|
||||
: _Storage(__i, std::forward<_Args>(__args)...)
|
||||
{ }
|
||||
_Move_ctor_base(const _Move_ctor_base&) = default;
|
||||
_Move_ctor_base& operator=(const _Move_ctor_base&) = default;
|
||||
_Move_ctor_base& operator=(_Move_ctor_base&&) = default;
|
||||
};
|
||||
|
||||
_Variant_base&
|
||||
operator=(const _Variant_base& __rhs)
|
||||
template<typename... _Types>
|
||||
struct _Move_ctor_base<true, _Types...> : _Copy_ctor_alias<_Types...>
|
||||
{
|
||||
using _Base = _Copy_ctor_alias<_Types...>;
|
||||
using _Base::_Base;
|
||||
};
|
||||
|
||||
template<typename... _Types>
|
||||
using _Move_ctor_alias =
|
||||
_Move_ctor_base<_Traits<_Types...>::_S_trivial_move_ctor, _Types...>;
|
||||
|
||||
template<bool, typename... _Types>
|
||||
struct _Copy_assign_base : _Move_ctor_alias<_Types...>
|
||||
{
|
||||
using _Base = _Move_ctor_alias<_Types...>;
|
||||
using _Base::_Base;
|
||||
|
||||
_Copy_assign_base&
|
||||
operator=(const _Copy_assign_base& __rhs)
|
||||
noexcept(_Traits<_Types...>::_S_nothrow_copy_assign)
|
||||
{
|
||||
if (this->_M_index == __rhs._M_index)
|
||||
{
|
||||
|
@ -439,16 +541,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{
|
||||
static constexpr void (*_S_vtable[])(void*, void*) =
|
||||
{ &__erased_assign<_Types&, const _Types&>... };
|
||||
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
|
||||
_S_vtable[__rhs._M_index](this->_M_storage(), __rhs._M_storage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_Variant_base __tmp(__rhs);
|
||||
this->~_Variant_base();
|
||||
_Copy_assign_base __tmp(__rhs);
|
||||
this->~_Copy_assign_base();
|
||||
__try
|
||||
{
|
||||
::new (this) _Variant_base(std::move(__tmp));
|
||||
::new (this) _Copy_assign_base(std::move(__tmp));
|
||||
}
|
||||
__catch (...)
|
||||
{
|
||||
|
@ -460,12 +562,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return *this;
|
||||
}
|
||||
|
||||
void _M_destructive_move(_Variant_base&& __rhs)
|
||||
_Copy_assign_base(const _Copy_assign_base&) = default;
|
||||
_Copy_assign_base(_Copy_assign_base&&) = default;
|
||||
_Copy_assign_base& operator=(_Copy_assign_base&&) = default;
|
||||
};
|
||||
|
||||
template<typename... _Types>
|
||||
struct _Copy_assign_base<true, _Types...> : _Move_ctor_alias<_Types...>
|
||||
{
|
||||
using _Base = _Move_ctor_alias<_Types...>;
|
||||
using _Base::_Base;
|
||||
};
|
||||
|
||||
template<typename... _Types>
|
||||
using _Copy_assign_alias =
|
||||
_Copy_assign_base<_Traits<_Types...>::_S_trivial_copy_assign,
|
||||
_Types...>;
|
||||
|
||||
template<bool, typename... _Types>
|
||||
struct _Move_assign_base : _Copy_assign_alias<_Types...>
|
||||
{
|
||||
using _Base = _Copy_assign_alias<_Types...>;
|
||||
using _Base::_Base;
|
||||
|
||||
void _M_destructive_move(_Move_assign_base&& __rhs)
|
||||
{
|
||||
this->~_Variant_base();
|
||||
this->~_Move_assign_base();
|
||||
__try
|
||||
{
|
||||
::new (this) _Variant_base(std::move(__rhs));
|
||||
::new (this) _Move_assign_base(std::move(__rhs));
|
||||
}
|
||||
__catch (...)
|
||||
{
|
||||
|
@ -474,40 +599,74 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
}
|
||||
|
||||
_Variant_base&
|
||||
operator=(_Variant_base&& __rhs)
|
||||
noexcept((is_nothrow_move_constructible_v<_Types> && ...)
|
||||
&& (is_nothrow_move_assignable_v<_Types> && ...))
|
||||
_Move_assign_base&
|
||||
operator=(_Move_assign_base&& __rhs)
|
||||
noexcept(_Traits<_Types...>::_S_nothrow_move_assign)
|
||||
{
|
||||
if (this->_M_index == __rhs._M_index)
|
||||
{
|
||||
if (__rhs._M_valid())
|
||||
{
|
||||
static constexpr void (*_S_vtable[])(void*, void*) =
|
||||
{ &__erased_assign<_Types&, _Types&&>... };
|
||||
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
|
||||
{ &__erased_assign<_Types&, const _Types&>... };
|
||||
_S_vtable[__rhs._M_index](this->_M_storage(), __rhs._M_storage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_M_destructive_move(std::move(__rhs));
|
||||
_Move_assign_base __tmp(__rhs);
|
||||
this->~_Move_assign_base();
|
||||
__try
|
||||
{
|
||||
::new (this) _Move_assign_base(std::move(__tmp));
|
||||
}
|
||||
__catch (...)
|
||||
{
|
||||
this->_M_index = variant_npos;
|
||||
__throw_exception_again;
|
||||
}
|
||||
}
|
||||
__glibcxx_assert(this->_M_index == __rhs._M_index);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void*
|
||||
_M_storage() const
|
||||
{
|
||||
return const_cast<void*>(static_cast<const void*>(
|
||||
std::addressof(_Storage::_M_u)));
|
||||
}
|
||||
_Move_assign_base(const _Move_assign_base&) = default;
|
||||
_Move_assign_base(_Move_assign_base&&) = default;
|
||||
_Move_assign_base& operator=(const _Move_assign_base&) = default;
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
_M_valid() const noexcept
|
||||
{
|
||||
return this->_M_index !=
|
||||
typename _Storage::__index_type(variant_npos);
|
||||
}
|
||||
template<typename... _Types>
|
||||
struct _Move_assign_base<true, _Types...> : _Copy_assign_alias<_Types...>
|
||||
{
|
||||
using _Base = _Copy_assign_alias<_Types...>;
|
||||
using _Base::_Base;
|
||||
};
|
||||
|
||||
template<typename... _Types>
|
||||
using _Move_assign_alias =
|
||||
_Move_assign_base<_Traits<_Types...>::_S_trivial_move_assign,
|
||||
_Types...>;
|
||||
|
||||
template<typename... _Types>
|
||||
struct _Variant_base : _Move_assign_alias<_Types...>
|
||||
{
|
||||
using _Base = _Move_assign_alias<_Types...>;
|
||||
|
||||
constexpr
|
||||
_Variant_base()
|
||||
noexcept(_Traits<_Types...>::_S_nothrow_default_ctor)
|
||||
: _Variant_base(in_place_index<0>) { }
|
||||
|
||||
template<size_t _Np, typename... _Args>
|
||||
constexpr explicit
|
||||
_Variant_base(in_place_index_t<_Np> __i, _Args&&... __args)
|
||||
: _Base(__i, std::forward<_Args>(__args)...)
|
||||
{ }
|
||||
|
||||
_Variant_base(const _Variant_base&) = default;
|
||||
_Variant_base(_Variant_base&&) = default;
|
||||
_Variant_base& operator=(const _Variant_base&) = default;
|
||||
_Variant_base& operator=(_Variant_base&&) = default;
|
||||
};
|
||||
|
||||
// For how many times does _Tp appear in _Tuple?
|
||||
|
@ -882,16 +1041,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
class variant
|
||||
: private __detail::__variant::_Variant_base<_Types...>,
|
||||
private _Enable_default_constructor<
|
||||
is_default_constructible_v<
|
||||
variant_alternative_t<0, variant<_Types...>>>, variant<_Types...>>,
|
||||
__detail::__variant::_Traits<_Types...>::_S_default_ctor,
|
||||
variant<_Types...>>,
|
||||
private _Enable_copy_move<
|
||||
(is_copy_constructible_v<_Types> && ...),
|
||||
(is_copy_constructible_v<_Types> && ...)
|
||||
&& (is_move_constructible_v<_Types> && ...)
|
||||
&& (is_copy_assignable_v<_Types> && ...),
|
||||
(is_move_constructible_v<_Types> && ...),
|
||||
(is_move_constructible_v<_Types> && ...)
|
||||
&& (is_move_assignable_v<_Types> && ...),
|
||||
__detail::__variant::_Traits<_Types...>::_S_copy_ctor,
|
||||
__detail::__variant::_Traits<_Types...>::_S_copy_assign,
|
||||
__detail::__variant::_Traits<_Types...>::_S_move_ctor,
|
||||
__detail::__variant::_Traits<_Types...>::_S_move_assign,
|
||||
variant<_Types...>>
|
||||
{
|
||||
private:
|
||||
|
@ -904,9 +1060,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
using _Base = __detail::__variant::_Variant_base<_Types...>;
|
||||
using _Default_ctor_enabler =
|
||||
_Enable_default_constructor<
|
||||
is_default_constructible_v<
|
||||
variant_alternative_t<0, variant<_Types...>>>, variant<_Types...>>;
|
||||
_Enable_default_constructor<
|
||||
__detail::__variant::_Traits<_Types...>::_S_default_ctor,
|
||||
variant<_Types...>>;
|
||||
|
||||
template<typename _Tp>
|
||||
static constexpr bool
|
||||
|
@ -933,12 +1089,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
static constexpr size_t __index_of =
|
||||
__detail::__variant::__index_of_v<_Tp, _Types...>;
|
||||
|
||||
using _Traits = __detail::__variant::_Traits<_Types...>;
|
||||
|
||||
public:
|
||||
constexpr variant()
|
||||
noexcept(is_nothrow_default_constructible_v<__to_type<0>>) = default;
|
||||
variant(const variant&) = default;
|
||||
variant(variant&&)
|
||||
noexcept((is_nothrow_move_constructible_v<_Types> && ...)) = default;
|
||||
variant() = default;
|
||||
variant(const variant& __rhs) = default;
|
||||
variant(variant&&) = default;
|
||||
variant& operator=(const variant&) = default;
|
||||
variant& operator=(variant&&) = default;
|
||||
~variant() = default;
|
||||
|
||||
template<typename _Tp,
|
||||
typename = enable_if_t<!is_same_v<decay_t<_Tp>, variant>>,
|
||||
|
@ -947,7 +1106,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
constexpr
|
||||
variant(_Tp&& __t)
|
||||
noexcept(is_nothrow_constructible_v<__accepted_type<_Tp&&>, _Tp&&>)
|
||||
: variant(in_place_index<__accepted_index<_Tp&&>>, std::forward<_Tp>(__t))
|
||||
: variant(in_place_index<__accepted_index<_Tp&&>>,
|
||||
std::forward<_Tp>(__t))
|
||||
{ __glibcxx_assert(holds_alternative<__accepted_type<_Tp&&>>(*this)); }
|
||||
|
||||
template<typename _Tp, typename... _Args,
|
||||
|
@ -955,7 +1115,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
&& is_constructible_v<_Tp, _Args&&...>>>
|
||||
constexpr explicit
|
||||
variant(in_place_type_t<_Tp>, _Args&&... __args)
|
||||
: variant(in_place_index<__index_of<_Tp>>, std::forward<_Args>(__args)...)
|
||||
: variant(in_place_index<__index_of<_Tp>>,
|
||||
std::forward<_Args>(__args)...)
|
||||
{ __glibcxx_assert(holds_alternative<_Tp>(*this)); }
|
||||
|
||||
template<typename _Tp, typename _Up, typename... _Args,
|
||||
|
@ -988,13 +1149,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_Default_ctor_enabler(_Enable_default_constructor_tag{})
|
||||
{ __glibcxx_assert(index() == _Np); }
|
||||
|
||||
~variant() = default;
|
||||
|
||||
variant& operator=(const variant&) = default;
|
||||
variant& operator=(variant&&)
|
||||
noexcept((is_nothrow_move_constructible_v<_Types> && ...)
|
||||
&& (is_nothrow_move_assignable_v<_Types> && ...)) = default;
|
||||
|
||||
template<typename _Tp>
|
||||
enable_if_t<__exactly_once<__accepted_type<_Tp&&>>
|
||||
&& is_constructible_v<__accepted_type<_Tp&&>, _Tp&&>
|
||||
|
@ -1089,7 +1243,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
constexpr size_t index() const noexcept
|
||||
{
|
||||
if (this->_M_index ==
|
||||
typename _Base::_Storage::__index_type(variant_npos))
|
||||
typename _Base::__index_type(variant_npos))
|
||||
return variant_npos;
|
||||
return this->_M_index;
|
||||
}
|
||||
|
|
|
@ -88,10 +88,12 @@ void copy_ctor()
|
|||
{
|
||||
static_assert(is_copy_constructible_v<variant<int, string>>, "");
|
||||
static_assert(!is_copy_constructible_v<variant<AllDeleted, string>>, "");
|
||||
static_assert(is_trivially_copy_constructible_v<variant<int>>, "");
|
||||
static_assert(!is_trivially_copy_constructible_v<variant<std::string>>, "");
|
||||
|
||||
{
|
||||
variant<int> a;
|
||||
static_assert(!noexcept(variant<int>(a)), "");
|
||||
static_assert(noexcept(variant<int>(a)), "");
|
||||
}
|
||||
{
|
||||
variant<string> a;
|
||||
|
@ -103,7 +105,7 @@ void copy_ctor()
|
|||
}
|
||||
{
|
||||
variant<int, char> a;
|
||||
static_assert(!noexcept(variant<int, char>(a)), "");
|
||||
static_assert(noexcept(variant<int, char>(a)), "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,6 +113,8 @@ void move_ctor()
|
|||
{
|
||||
static_assert(is_move_constructible_v<variant<int, string>>, "");
|
||||
static_assert(!is_move_constructible_v<variant<AllDeleted, string>>, "");
|
||||
static_assert(is_trivially_move_constructible_v<variant<int>>, "");
|
||||
static_assert(!is_trivially_move_constructible_v<variant<std::string>>, "");
|
||||
static_assert(!noexcept(variant<int, Empty>(declval<variant<int, Empty>>())), "");
|
||||
static_assert(noexcept(variant<int, DefaultNoexcept>(declval<variant<int, DefaultNoexcept>>())), "");
|
||||
}
|
||||
|
@ -148,13 +152,15 @@ void copy_assign()
|
|||
{
|
||||
static_assert(is_copy_assignable_v<variant<int, string>>, "");
|
||||
static_assert(!is_copy_assignable_v<variant<AllDeleted, string>>, "");
|
||||
static_assert(is_trivially_copy_assignable_v<variant<int>>, "");
|
||||
static_assert(!is_trivially_copy_assignable_v<variant<string>>, "");
|
||||
{
|
||||
variant<Empty> a;
|
||||
static_assert(!noexcept(a = a), "");
|
||||
}
|
||||
{
|
||||
variant<DefaultNoexcept> a;
|
||||
static_assert(!noexcept(a = a), "");
|
||||
static_assert(noexcept(a = a), "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,6 +168,8 @@ void move_assign()
|
|||
{
|
||||
static_assert(is_move_assignable_v<variant<int, string>>, "");
|
||||
static_assert(!is_move_assignable_v<variant<AllDeleted, string>>, "");
|
||||
static_assert(is_trivially_move_assignable_v<variant<int>>, "");
|
||||
static_assert(!is_trivially_move_assignable_v<variant<string>>, "");
|
||||
{
|
||||
variant<Empty> a;
|
||||
static_assert(!noexcept(a = std::move(a)), "");
|
||||
|
@ -454,3 +462,92 @@ void test_emplace()
|
|||
static_assert(!has_type_emplace<variant<AllDeleted>, AllDeleted>(0), "");
|
||||
static_assert(!has_index_emplace<variant<AllDeleted>, 0>(0), "");
|
||||
}
|
||||
|
||||
void test_triviality()
|
||||
{
|
||||
#define TEST_TEMPLATE(DT, CC, MC, CA, MA, CC_VAL, MC_VAL, CA_VAL, MA_VAL) \
|
||||
{ \
|
||||
struct A \
|
||||
{ \
|
||||
~A() DT; \
|
||||
A(const A&) CC; \
|
||||
A(A&&) MC; \
|
||||
A& operator=(const A&) CA; \
|
||||
A& operator=(A&&) MA; \
|
||||
}; \
|
||||
static_assert(CC_VAL == is_trivially_copy_constructible_v<variant<A>>, ""); \
|
||||
static_assert(MC_VAL == is_trivially_move_constructible_v<variant<A>>, ""); \
|
||||
static_assert(CA_VAL == is_trivially_copy_assignable_v<variant<A>>, ""); \
|
||||
static_assert(MA_VAL == is_trivially_move_assignable_v<variant<A>>, ""); \
|
||||
}
|
||||
TEST_TEMPLATE(=default, =default, =default, =default, =default, true, true, true, true)
|
||||
TEST_TEMPLATE(=default, =default, =default, =default, {}, true, true, true, false)
|
||||
TEST_TEMPLATE(=default, =default, =default, {}, =default, true, true, false, true)
|
||||
TEST_TEMPLATE(=default, =default, =default, {}, {}, true, true, false, false)
|
||||
TEST_TEMPLATE(=default, =default, {}, =default, =default, true, false, true, true)
|
||||
TEST_TEMPLATE(=default, =default, {}, =default, {}, true, false, true, false)
|
||||
TEST_TEMPLATE(=default, =default, {}, {}, =default, true, false, false, true)
|
||||
TEST_TEMPLATE(=default, =default, {}, {}, {}, true, false, false, false)
|
||||
TEST_TEMPLATE(=default, {}, =default, =default, =default, false, true, true, true)
|
||||
TEST_TEMPLATE(=default, {}, =default, =default, {}, false, true, true, false)
|
||||
TEST_TEMPLATE(=default, {}, =default, {}, =default, false, true, false, true)
|
||||
TEST_TEMPLATE(=default, {}, =default, {}, {}, false, true, false, false)
|
||||
TEST_TEMPLATE(=default, {}, {}, =default, =default, false, false, true, true)
|
||||
TEST_TEMPLATE(=default, {}, {}, =default, {}, false, false, true, false)
|
||||
TEST_TEMPLATE(=default, {}, {}, {}, =default, false, false, false, true)
|
||||
TEST_TEMPLATE(=default, {}, {}, {}, {}, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, =default, =default, =default, =default, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, =default, =default, =default, {}, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, =default, =default, {}, =default, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, =default, =default, {}, {}, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, =default, {}, =default, =default, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, =default, {}, =default, {}, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, =default, {}, {}, =default, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, =default, {}, {}, {}, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, {}, =default, =default, =default, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, {}, =default, =default, {}, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, {}, =default, {}, =default, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, {}, =default, {}, {}, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, {}, {}, =default, =default, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, {}, {}, =default, {}, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, {}, {}, {}, =default, false, false, false, false)
|
||||
TEST_TEMPLATE( {}, {}, {}, {}, {}, false, false, false, false)
|
||||
#undef TEST_TEMPLATE
|
||||
|
||||
#define TEST_TEMPLATE(CC, MC, CA, MA) \
|
||||
{ \
|
||||
struct A \
|
||||
{ \
|
||||
A(const A&) CC; \
|
||||
A(A&&) MC; \
|
||||
A& operator=(const A&) CA; \
|
||||
A& operator=(A&&) MA; \
|
||||
}; \
|
||||
static_assert(!is_trivially_copy_constructible_v<variant<AllDeleted, A>>, ""); \
|
||||
static_assert(!is_trivially_move_constructible_v<variant<AllDeleted, A>>, ""); \
|
||||
static_assert(!is_trivially_copy_assignable_v<variant<AllDeleted, A>>, ""); \
|
||||
static_assert(!is_trivially_move_assignable_v<variant<AllDeleted, A>>, ""); \
|
||||
}
|
||||
TEST_TEMPLATE(=default, =default, =default, =default)
|
||||
TEST_TEMPLATE(=default, =default, =default, {})
|
||||
TEST_TEMPLATE(=default, =default, {}, =default)
|
||||
TEST_TEMPLATE(=default, =default, {}, {})
|
||||
TEST_TEMPLATE(=default, {}, =default, =default)
|
||||
TEST_TEMPLATE(=default, {}, =default, {})
|
||||
TEST_TEMPLATE(=default, {}, {}, =default)
|
||||
TEST_TEMPLATE(=default, {}, {}, {})
|
||||
TEST_TEMPLATE( {}, =default, =default, =default)
|
||||
TEST_TEMPLATE( {}, =default, =default, {})
|
||||
TEST_TEMPLATE( {}, =default, {}, =default)
|
||||
TEST_TEMPLATE( {}, =default, {}, {})
|
||||
TEST_TEMPLATE( {}, {}, =default, =default)
|
||||
TEST_TEMPLATE( {}, {}, =default, {})
|
||||
TEST_TEMPLATE( {}, {}, {}, =default)
|
||||
TEST_TEMPLATE( {}, {}, {}, {})
|
||||
#undef TEST_TEMPLATE
|
||||
|
||||
static_assert(is_trivially_copy_constructible_v<variant<DefaultNoexcept, int, char, float, double>>, "");
|
||||
static_assert(is_trivially_move_constructible_v<variant<DefaultNoexcept, int, char, float, double>>, "");
|
||||
static_assert(is_trivially_copy_assignable_v<variant<DefaultNoexcept, int, char, float, double>>, "");
|
||||
static_assert(is_trivially_move_assignable_v<variant<DefaultNoexcept, int, char, float, double>>, "");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue