enable_special_members.h: Make _Enable_default_constructor constexpr.
* include/bits/enable_special_members.h: Make _Enable_default_constructor constexpr. * include/std/variant (variant::emplace, variant::swap, std::swap, std::hash): Sfinae on emplace and std::swap; handle __poison_hash bases of duplicated types. * testsuite/20_util/variant/compile.cc: Add tests. * testsuite/20_util/variant/hash.cc: Add tests. From-SVN: r243294
This commit is contained in:
parent
9189f55908
commit
458ef69052
|
@ -1,3 +1,11 @@
|
|||
2016-12-07 Tim Shen <timshen@google.com>
|
||||
|
||||
* include/bits/enable_special_members.h: Make
|
||||
_Enable_default_constructor constexpr.
|
||||
* include/std/variant (variant::emplace, variant::swap, std::swap,
|
||||
std::hash): Sfinae on emplace and std::swap; handle __poison_hash bases
|
||||
of duplicated types.
|
||||
|
||||
2016-12-07 Tim Shen <timshen@google.com>
|
||||
|
||||
* include/std/variant (std::get, operator==): Implement constexpr
|
||||
|
|
|
@ -38,7 +38,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
struct _Enable_default_constructor_tag
|
||||
{
|
||||
explicit _Enable_default_constructor_tag() = default;
|
||||
explicit constexpr _Enable_default_constructor_tag() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -118,7 +118,8 @@ template<typename _Tag>
|
|||
operator=(_Enable_default_constructor&&) noexcept = default;
|
||||
|
||||
// Can be used in other ctors.
|
||||
explicit _Enable_default_constructor(_Enable_default_constructor_tag) { }
|
||||
constexpr explicit
|
||||
_Enable_default_constructor(_Enable_default_constructor_tag) { }
|
||||
};
|
||||
|
||||
template<typename _Tag>
|
||||
|
|
|
@ -330,14 +330,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ }
|
||||
|
||||
template<size_t... __indices>
|
||||
constexpr void _M_destroy_impl(std::index_sequence<__indices...>)
|
||||
constexpr void _M_reset_impl(std::index_sequence<__indices...>)
|
||||
{
|
||||
if (_M_index != variant_npos)
|
||||
_S_vtable<__indices...>[_M_index](*this);
|
||||
}
|
||||
|
||||
void _M_reset()
|
||||
{
|
||||
_M_reset_impl(std::index_sequence_for<_Types...>{});
|
||||
_M_index = variant_npos;
|
||||
}
|
||||
|
||||
~_Variant_storage()
|
||||
{ _M_destroy_impl(std::index_sequence_for<_Types...>{}); }
|
||||
{ _M_reset(); }
|
||||
|
||||
_Variadic_union<_Types...> _M_u;
|
||||
size_t _M_index;
|
||||
|
@ -354,6 +360,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_M_index(_Np)
|
||||
{ }
|
||||
|
||||
void _M_reset()
|
||||
{ _M_index = variant_npos; }
|
||||
|
||||
_Variadic_union<_Types...> _M_u;
|
||||
size_t _M_index;
|
||||
};
|
||||
|
@ -436,6 +445,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return *this;
|
||||
}
|
||||
|
||||
void _M_destructive_move(_Variant_base&& __rhs)
|
||||
{
|
||||
this->~_Variant_base();
|
||||
__try
|
||||
{
|
||||
::new (this) _Variant_base(std::move(__rhs));
|
||||
}
|
||||
__catch (...)
|
||||
{
|
||||
this->_M_index = variant_npos;
|
||||
__throw_exception_again;
|
||||
}
|
||||
}
|
||||
|
||||
_Variant_base&
|
||||
operator=(_Variant_base&& __rhs)
|
||||
noexcept(__and_<is_nothrow_move_constructible<_Types>...,
|
||||
|
@ -453,16 +476,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
else
|
||||
{
|
||||
this->~_Variant_base();
|
||||
__try
|
||||
{
|
||||
::new (this) _Variant_base(std::move(__rhs));
|
||||
}
|
||||
__catch (...)
|
||||
{
|
||||
this->_M_index = variant_npos;
|
||||
__throw_exception_again;
|
||||
}
|
||||
_M_destructive_move(std::move(__rhs));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -682,6 +696,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
};
|
||||
|
||||
template<size_t _Np, typename _Tp>
|
||||
struct _Base_dedup : public _Tp { };
|
||||
|
||||
template<typename _Variant, typename __indices>
|
||||
struct _Variant_hash_base;
|
||||
|
||||
template<typename... _Types, size_t... __indices>
|
||||
struct _Variant_hash_base<variant<_Types...>,
|
||||
std::index_sequence<__indices...>>
|
||||
: _Base_dedup<__indices, __poison_hash<remove_const_t<_Types>>>... { };
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace __variant
|
||||
} // namespace __detail
|
||||
|
@ -858,8 +883,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ return false; }
|
||||
|
||||
template<typename... _Types>
|
||||
inline enable_if_t<__and_<is_move_constructible<_Types>...,
|
||||
is_swappable<_Types>...>::value>
|
||||
inline enable_if_t<(is_move_constructible_v<_Types> && ...)
|
||||
&& (is_swappable_v<_Types> && ...)>
|
||||
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
|
||||
noexcept(noexcept(__lhs.swap(__rhs)))
|
||||
{ __lhs.swap(__rhs); }
|
||||
|
@ -1028,25 +1053,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
|
||||
template<typename _Tp, typename... _Args>
|
||||
void emplace(_Args&&... __args)
|
||||
enable_if_t<is_constructible_v<_Tp, _Args...> && __exactly_once<_Tp>>
|
||||
emplace(_Args&&... __args)
|
||||
{
|
||||
static_assert(__exactly_once<_Tp>,
|
||||
"T should occur for exactly once in alternatives");
|
||||
this->emplace<__index_of<_Tp>>(std::forward<_Args>(__args)...);
|
||||
__glibcxx_assert(holds_alternative<_Tp>(*this));
|
||||
}
|
||||
|
||||
template<typename _Tp, typename _Up, typename... _Args>
|
||||
void emplace(initializer_list<_Up> __il, _Args&&... __args)
|
||||
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
|
||||
&& __exactly_once<_Tp>>
|
||||
emplace(initializer_list<_Up> __il, _Args&&... __args)
|
||||
{
|
||||
static_assert(__exactly_once<_Tp>,
|
||||
"T should occur for exactly once in alternatives");
|
||||
this->emplace<__index_of<_Tp>>(__il, std::forward<_Args>(__args)...);
|
||||
__glibcxx_assert(holds_alternative<_Tp>(*this));
|
||||
}
|
||||
|
||||
template<size_t _Np, typename... _Args>
|
||||
void emplace(_Args&&... __args)
|
||||
enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
|
||||
_Args...>>
|
||||
emplace(_Args&&... __args)
|
||||
{
|
||||
static_assert(_Np < sizeof...(_Types),
|
||||
"The index should be in [0, number of alternatives)");
|
||||
|
@ -1065,7 +1091,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
|
||||
template<size_t _Np, typename _Up, typename... _Args>
|
||||
void emplace(initializer_list<_Up> __il, _Args&&... __args)
|
||||
enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
|
||||
initializer_list<_Up>&, _Args...>>
|
||||
emplace(initializer_list<_Up> __il, _Args&&... __args)
|
||||
{
|
||||
static_assert(_Np < sizeof...(_Types),
|
||||
"The index should be in [0, number of alternatives)");
|
||||
|
@ -1092,7 +1120,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
void
|
||||
swap(variant& __rhs)
|
||||
noexcept(__and_<__is_nothrow_swappable<_Types>...>::value
|
||||
&& is_nothrow_move_assignable_v<variant>)
|
||||
&& is_nothrow_move_constructible_v<variant>)
|
||||
{
|
||||
if (this->index() == __rhs.index())
|
||||
{
|
||||
|
@ -1107,17 +1135,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
else if (!this->_M_valid())
|
||||
{
|
||||
*this = std::move(__rhs);
|
||||
this->_M_destructive_move(std::move(__rhs));
|
||||
__rhs._M_reset();
|
||||
}
|
||||
else if (!__rhs._M_valid())
|
||||
{
|
||||
__rhs = std::move(*this);
|
||||
__rhs._M_destructive_move(std::move(*this));
|
||||
this->_M_reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto __tmp = std::move(__rhs);
|
||||
__rhs = std::move(*this);
|
||||
*this = std::move(__tmp);
|
||||
__rhs._M_destructive_move(std::move(*this));
|
||||
this->_M_destructive_move(std::move(__tmp));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1253,14 +1283,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<typename... _Types>
|
||||
struct hash<variant<_Types...>>
|
||||
: private __poison_hash<remove_const_t<_Types>>...
|
||||
: private __detail::__variant::_Variant_hash_base<
|
||||
variant<_Types...>, std::index_sequence_for<_Types...>>
|
||||
{
|
||||
using result_type = size_t;
|
||||
using argument_type = variant<_Types...>;
|
||||
|
||||
size_t
|
||||
operator()(const variant<_Types...>& __t) const
|
||||
noexcept((... && noexcept(hash<decay_t<_Types>>{}(std::declval<_Types>()))))
|
||||
noexcept((is_nothrow_callable_v<hash<decay_t<_Types>>(_Types)> && ...))
|
||||
{
|
||||
if (!__t.valueless_by_exception())
|
||||
{
|
||||
|
|
|
@ -51,6 +51,15 @@ struct DefaultNoexcept
|
|||
DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default;
|
||||
};
|
||||
|
||||
struct MoveCtorOnly
|
||||
{
|
||||
MoveCtorOnly() noexcept = delete;
|
||||
MoveCtorOnly(const DefaultNoexcept&) noexcept = delete;
|
||||
MoveCtorOnly(DefaultNoexcept&&) noexcept { }
|
||||
MoveCtorOnly& operator=(const DefaultNoexcept&) noexcept = delete;
|
||||
MoveCtorOnly& operator=(DefaultNoexcept&&) noexcept = delete;
|
||||
};
|
||||
|
||||
struct nonliteral
|
||||
{
|
||||
nonliteral() { }
|
||||
|
@ -237,9 +246,9 @@ static_assert( !std::is_swappable_v<variant<D, int>> );
|
|||
|
||||
void test_swap()
|
||||
{
|
||||
variant<int, string> a, b;
|
||||
a.swap(b);
|
||||
swap(a, b);
|
||||
static_assert(is_swappable_v<variant<int, string>>, "");
|
||||
static_assert(is_swappable_v<variant<MoveCtorOnly>>, "");
|
||||
static_assert(!is_swappable_v<variant<AllDeleted>>, "");
|
||||
}
|
||||
|
||||
void test_visit()
|
||||
|
@ -385,7 +394,8 @@ void test_adl()
|
|||
variant<X> v4{in_place_type<X>, il, x};
|
||||
}
|
||||
|
||||
void test_variant_alternative() {
|
||||
void test_variant_alternative()
|
||||
{
|
||||
static_assert(is_same_v<variant_alternative_t<0, variant<int, string>>, int>, "");
|
||||
static_assert(is_same_v<variant_alternative_t<1, variant<int, string>>, string>, "");
|
||||
|
||||
|
@ -393,3 +403,28 @@ void test_variant_alternative() {
|
|||
static_assert(is_same_v<variant_alternative_t<0, volatile variant<int>>, volatile int>, "");
|
||||
static_assert(is_same_v<variant_alternative_t<0, const volatile variant<int>>, const volatile int>, "");
|
||||
}
|
||||
|
||||
template<typename V, typename T>
|
||||
constexpr auto has_type_emplace(int) -> decltype((declval<V>().template emplace<T>(), true))
|
||||
{ return true; };
|
||||
|
||||
template<typename V, typename T>
|
||||
constexpr bool has_type_emplace(...)
|
||||
{ return false; };
|
||||
|
||||
template<typename V, size_t N>
|
||||
constexpr auto has_index_emplace(int) -> decltype((declval<V>().template emplace<N>(), true))
|
||||
{ return true; };
|
||||
|
||||
template<typename V, size_t T>
|
||||
constexpr bool has_index_emplace(...)
|
||||
{ return false; };
|
||||
|
||||
void test_emplace()
|
||||
{
|
||||
static_assert(has_type_emplace<variant<int>, int>(0), "");
|
||||
static_assert(!has_type_emplace<variant<long>, int>(0), "");
|
||||
static_assert(has_index_emplace<variant<int>, 0>(0), "");
|
||||
static_assert(!has_type_emplace<variant<AllDeleted>, AllDeleted>(0), "");
|
||||
static_assert(!has_index_emplace<variant<AllDeleted>, 0>(0), "");
|
||||
}
|
||||
|
|
|
@ -29,6 +29,10 @@ template<class T>
|
|||
auto f(...) -> decltype(std::false_type());
|
||||
|
||||
static_assert(!decltype(f<S>(0))::value, "");
|
||||
static_assert(!decltype(f<std::variant<S>>(0))::value, "");
|
||||
static_assert(!decltype(f<std::variant<S, S>>(0))::value, "");
|
||||
static_assert(decltype(f<std::variant<int>>(0))::value, "");
|
||||
static_assert(decltype(f<std::variant<int, int>>(0))::value, "");
|
||||
|
||||
int main()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue