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:
Tim Shen 2016-12-06 11:26:48 +00:00 committed by Tim Shen
parent 9189f55908
commit 458ef69052
5 changed files with 114 additions and 35 deletions

View File

@ -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

View File

@ -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>

View File

@ -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())
{

View File

@ -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), "");
}

View File

@ -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()
{