This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Patches] Add variant constexpr support for visit, comparisons and get
- From: Tim Shen <timshen at google dot com>
- To: "libstdc++" <libstdc++ at gcc dot gnu dot org>, gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Sat, 26 Nov 2016 21:38:21 -0800
- Subject: [Patches] Add variant constexpr support for visit, comparisons and get
- Authentication-results: sourceware.org; auth=none
This 4-patch series contains the following in order:
a.diff: Remove uses-allocator ctors. They are going away, and removing
it reduces the maintenance burden from now on.
b.diff: Add constexpr support for get<> and comparisons. This patch
also involves small refactoring of _Variant_storage.
c.diff: Fix some libc++ test failures.
d.diff: Add constexpr support for visit. This patch also removes
__storage, __get_alternative, and __reserved_type_map, since we don't
need to support reference/void types for now.
The underlying design doesn't change - we still use the vtable
approach to achieve O(1) runtime cost even under -O0.
Bootstrapped and tested for each of them.
Thanks!
--
Regards,
Tim Shen
commit 638ecd4cf354d853bb12b089a356df99531f9afa
Author: Tim Shen <timshen@google.com>
Date: Thu Nov 24 00:56:08 2016 -0800
2016-11-26 Tim Shen <timshen@google.com>
* include/std/variant (__erased_use_alloc_ctor,
_Variant_base::_Variant_base, variant::variant): Remove uses-allocator
related functions.
* testsuite/20_util/variant/compile.cc: Remove related tests.
* testsuite/20_util/variant/run.cc: Remove related tests.
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 34ad3fd..2d9303a 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -202,14 +202,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__erased_ctor(void* __lhs, void* __rhs)
{ ::new (__lhs) decay_t<_Lhs>(__get_alternative<_Rhs>(__rhs)); }
- template<typename _Alloc, typename _Lhs, typename _Rhs>
- constexpr void
- __erased_use_alloc_ctor(const _Alloc& __a, void* __lhs, void* __rhs)
- {
- __uses_allocator_construct(__a, static_cast<decay_t<_Lhs>*>(__lhs),
- __get_alternative<_Rhs>(__rhs));
- }
-
// TODO: Find a potential chance to reuse this accross the project.
template<typename _Tp>
constexpr void
@@ -353,47 +345,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: _Storage(__i, std::forward<_Args>(__args)...), _M_index(_Np)
{ }
- template<typename _Alloc>
- _Variant_base(const _Alloc& __a, const _Variant_base& __rhs)
- : _Storage(), _M_index(__rhs._M_index)
- {
- if (__rhs._M_valid())
- {
- static constexpr void
- (*_S_vtable[])(const _Alloc&, void*, void*) =
- { &__erased_use_alloc_ctor<_Alloc, __storage<_Types>&,
- const __storage<_Types>&>... };
- _S_vtable[__rhs._M_index](__a, _M_storage(), __rhs._M_storage());
- }
- }
-
- template<typename _Alloc>
- _Variant_base(const _Alloc& __a, _Variant_base&& __rhs)
- : _Storage(), _M_index(__rhs._M_index)
- {
- if (__rhs._M_valid())
- {
- static constexpr void
- (*_S_vtable[])(const _Alloc&, void*, void*) =
- { &__erased_use_alloc_ctor<_Alloc, __storage<_Types>&,
- __storage<_Types>&&>... };
- _S_vtable[__rhs._M_index](__a, _M_storage(), __rhs._M_storage());
- }
- }
-
- template<typename _Alloc, size_t _Np, typename... _Args>
- constexpr explicit
- _Variant_base(const _Alloc& __a, in_place_index_t<_Np>,
- _Args&&... __args)
- : _Storage(), _M_index(_Np)
- {
- using _Storage =
- __storage<variant_alternative_t<_Np, variant<_Types...>>>;
- __uses_allocator_construct(__a, static_cast<_Storage*>(_M_storage()),
- std::forward<_Args>(__args)...);
- __glibcxx_assert(_M_index == _Np);
- }
-
_Variant_base&
operator=(const _Variant_base& __rhs)
{
@@ -1026,84 +977,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Default_ctor_enabler(_Enable_default_constructor_tag{})
{ __glibcxx_assert(index() == _Np); }
- template<typename _Alloc,
- typename = enable_if_t<
- __is_uses_allocator_constructible_v<__to_type<0>, _Alloc>>>
- variant(allocator_arg_t, const _Alloc& __a)
- : variant(allocator_arg, __a, in_place_index<0>)
- { }
-
- template<typename _Alloc,
- typename = enable_if_t<__and_<__is_uses_allocator_constructible<
- _Types, _Alloc,
- add_lvalue_reference_t<add_const_t<_Types>>>...>::value>>
- variant(allocator_arg_t, const _Alloc& __a, const variant& __rhs)
- : _Base(__a, __rhs),
- _Default_ctor_enabler(_Enable_default_constructor_tag{})
- { }
-
- template<typename _Alloc,
- typename = enable_if_t<__and_<
- __is_uses_allocator_constructible<
- _Types, _Alloc, add_rvalue_reference_t<_Types>>...>::value>>
- variant(allocator_arg_t, const _Alloc& __a, variant&& __rhs)
- : _Base(__a, std::move(__rhs)),
- _Default_ctor_enabler(_Enable_default_constructor_tag{})
- { }
-
- template<typename _Alloc, typename _Tp,
- typename = enable_if_t<
- __exactly_once<__accepted_type<_Tp&&>>
- && __is_uses_allocator_constructible_v<
- __accepted_type<_Tp&&>, _Alloc, _Tp&&>
- && !is_same_v<decay_t<_Tp>, variant>, variant&>>
- variant(allocator_arg_t, const _Alloc& __a, _Tp&& __t)
- : variant(allocator_arg, __a, in_place_index<__accepted_index<_Tp&&>>,
- std::forward<_Tp>(__t))
- { __glibcxx_assert(holds_alternative<__accepted_type<_Tp&&>>(*this)); }
-
- template<typename _Alloc, typename _Tp, typename... _Args,
- typename = enable_if_t<
- __exactly_once<_Tp>
- && __is_uses_allocator_constructible_v<
- _Tp, _Alloc, _Args&&...>>>
- variant(allocator_arg_t, const _Alloc& __a, in_place_type_t<_Tp>,
- _Args&&... __args)
- : variant(allocator_arg, __a, in_place_index<__index_of<_Tp>>,
- std::forward<_Args>(__args)...)
- { __glibcxx_assert(holds_alternative<_Tp>(*this)); }
-
- template<typename _Alloc, typename _Tp, typename _Up, typename... _Args,
- typename = enable_if_t<
- __exactly_once<_Tp>
- && __is_uses_allocator_constructible_v<
- _Tp, _Alloc, initializer_list<_Up>&, _Args&&...>>>
- variant(allocator_arg_t, const _Alloc& __a, in_place_type_t<_Tp>,
- initializer_list<_Up> __il, _Args&&... __args)
- : variant(allocator_arg, __a, in_place_index<__index_of<_Tp>>, __il,
- std::forward<_Args>(__args)...)
- { __glibcxx_assert(holds_alternative<_Tp>(*this)); }
-
- template<typename _Alloc, size_t _Np, typename... _Args,
- typename = enable_if_t<
- __is_uses_allocator_constructible_v<
- __to_type<_Np>, _Alloc, _Args&&...>>>
- variant(allocator_arg_t, const _Alloc& __a, in_place_index_t<_Np>,
- _Args&&... __args)
- : _Base(__a, in_place_index<_Np>, std::forward<_Args>(__args)...),
- _Default_ctor_enabler(_Enable_default_constructor_tag{})
- { __glibcxx_assert(index() == _Np); }
-
- template<typename _Alloc, size_t _Np, typename _Up, typename... _Args,
- typename = enable_if_t<
- __is_uses_allocator_constructible_v<
- __to_type<_Np>, _Alloc, initializer_list<_Up>&, _Args&&...>>>
- variant(allocator_arg_t, const _Alloc& __a, in_place_index_t<_Np>,
- initializer_list<_Up> __il, _Args&&... __args)
- : _Base(__a, in_place_index<_Np>, __il, std::forward<_Args>(__args)...),
- _Default_ctor_enabler(_Enable_default_constructor_tag{})
- { __glibcxx_assert(index() == _Np); }
-
~variant() = default;
variant& operator=(const variant&) = default;
@@ -1293,10 +1166,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__detail::__variant::__get_storage(__variants)...);
}
- template<typename... _Types, typename _Alloc>
- struct uses_allocator<variant<_Types...>, _Alloc>
- : true_type { };
-
template<typename... _Types>
struct hash<variant<_Types...>>
: private __poison_hash<remove_const_t<_Types>>...
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index e3330be..5bd4e70 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -117,31 +117,6 @@ void in_place_type_ctor()
static_assert(!is_constructible_v<variant<string, string>, in_place_type_t<string>, const char*>, "");
}
-void uses_alloc_ctors()
-{
- std::allocator<char> alloc;
- variant<int> a(allocator_arg, alloc);
- static_assert(!is_constructible_v<variant<AllDeleted>, allocator_arg_t, std::allocator<char>>, "");
- {
- variant<string, int> b(allocator_arg, alloc, "a");
- static_assert(!is_constructible_v<variant<string, string>, allocator_arg_t, std::allocator<char>, const char*>, "");
- }
- {
- variant<string, int> b(allocator_arg, alloc, in_place_index<0>, "a");
- variant<string, string> c(allocator_arg, alloc, in_place_index<1>, "a");
- }
- {
- variant<string, int> b(allocator_arg, alloc, in_place_index<0>, {'a'});
- variant<string, string> c(allocator_arg, alloc, in_place_index<1>, {'a'});
- }
- {
- variant<int, string, int> b(allocator_arg, alloc, in_place_type<string>, "a");
- }
- {
- variant<int, string, int> b(allocator_arg, alloc, in_place_type<string>, {'a'});
- }
-}
-
void dtor()
{
static_assert(is_destructible_v<variant<int, string>>, "");
@@ -309,9 +284,7 @@ namespace adl_trap
void test_adl()
{
using adl_trap::X;
- using std::allocator_arg;
X x;
- std::allocator<int> a;
std::initializer_list<int> il;
adl_trap::Visitor vis;
@@ -324,11 +297,6 @@ void test_adl()
variant<X> v2{in_place_type<X>, x};
variant<X> v3{in_place_index<0>, il, x};
variant<X> v4{in_place_type<X>, il, x};
- variant<X> v5{allocator_arg, a, in_place_index<0>, x};
- variant<X> v6{allocator_arg, a, in_place_type<X>, x};
- variant<X> v7{allocator_arg, a, in_place_index<0>, il, x};
- variant<X> v8{allocator_arg, a, in_place_type<X>, il, x};
- variant<X> v9{allocator_arg, a, in_place_type<X>, 1};
}
void test_variant_alternative() {
diff --git a/libstdc++-v3/testsuite/20_util/variant/run.cc b/libstdc++-v3/testsuite/20_util/variant/run.cc
index 71e0176..fb5d7c4 100644
--- a/libstdc++-v3/testsuite/20_util/variant/run.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/run.cc
@@ -160,48 +160,6 @@ void in_place_type_ctor()
}
}
-struct UsesAllocatable
-{
- template<typename Alloc>
- UsesAllocatable(std::allocator_arg_t, const Alloc& a)
- : d(0), a(static_cast<const void*>(&a)) { }
-
- template<typename Alloc>
- UsesAllocatable(std::allocator_arg_t, const Alloc& a, const UsesAllocatable&)
- : d(1), a(static_cast<const void*>(&a)) { }
-
- template<typename Alloc>
- UsesAllocatable(std::allocator_arg_t, const Alloc& a, UsesAllocatable&&)
- : d(2), a(static_cast<const void*>(&a)) { }
-
- int d;
- const void* a;
-};
-
-namespace std
-{
- template<>
- struct uses_allocator<UsesAllocatable, std::allocator<char>> : true_type { };
-}
-
-void uses_allocator_ctor()
-{
- std::allocator<char> a;
- variant<UsesAllocatable> v(std::allocator_arg, a);
- VERIFY(get<0>(v).d == 0);
- VERIFY(get<0>(v).a == &a);
- {
- variant<UsesAllocatable> u(std::allocator_arg, a, v);
- VERIFY(get<0>(u).d == 1);
- VERIFY(get<0>(u).a == &a);
- }
- {
- variant<UsesAllocatable> u(std::allocator_arg, a, std::move(v));
- VERIFY(get<0>(u).d == 2);
- VERIFY(get<0>(u).a == &a);
- }
-}
-
void emplace()
{
variant<int, string> v;
@@ -450,7 +408,6 @@ int main()
arbitrary_ctor();
in_place_index_ctor();
in_place_type_ctor();
- uses_allocator_ctor();
copy_assign();
move_assign();
arbitrary_assign();
commit 7c510c3d9ac56684a966ae818a2b0d64d63463c2
Author: Tim Shen <timshen@google.com>
Date: Thu Nov 24 12:00:48 2016 -0800
2016-11-26 Tim Shen <timshen@google.com>
* include/std/variant: Implement constexpr comparison and get<>.
* testsuite/20_util/variant/compile.cc: Tests.
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 2d9303a..a913074 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -154,31 +154,63 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Alternative>
using __storage = _Alternative;
- template<typename _Type, bool __is_literal = std::is_literal_type_v<_Type>>
+ // _Uninitialized nullify the destructor calls.
+ // This is necessary, since we define _Variadic_union as a recursive union,
+ // and we don't want to inspect the union members one by one in its dtor,
+ // it's slow.
+ template<typename _Type, bool = std::is_literal_type_v<_Type>>
struct _Uninitialized;
template<typename _Type>
struct _Uninitialized<_Type, true>
{
- constexpr _Uninitialized() = default;
-
template<typename... _Args>
constexpr _Uninitialized(in_place_index_t<0>, _Args&&... __args)
: _M_storage(std::forward<_Args>(__args)...)
{ }
+ constexpr const _Type& _M_get() const &
+ { return _M_storage; }
+
+ constexpr _Type& _M_get() &
+ { return _M_storage; }
+
+ constexpr const _Type&& _M_get() const &&
+ { return std::move(_M_storage); }
+
+ constexpr _Type&& _M_get() &&
+ { return std::move(_M_storage); }
+
_Type _M_storage;
};
template<typename _Type>
struct _Uninitialized<_Type, false>
{
- constexpr _Uninitialized() = default;
-
template<typename... _Args>
constexpr _Uninitialized(in_place_index_t<0>, _Args&&... __args)
{ ::new (&_M_storage) _Type(std::forward<_Args>(__args)...); }
+ const _Type& _M_get() const &
+ {
+ return *static_cast<const _Type*>(
+ static_cast<const void*>(&_M_storage));
+ }
+
+ _Type& _M_get() &
+ { return *static_cast<_Type*>(static_cast<void*>(&_M_storage)); }
+
+ const _Type&& _M_get() const &&
+ {
+ return std::move(*static_cast<const _Type*>(
+ static_cast<const void*>(&_M_storage)));
+ }
+
+ _Type&& _M_get() &&
+ {
+ return std::move(*static_cast<_Type*>(static_cast<void*>(&_M_storage)));
+ }
+
typename std::aligned_storage<sizeof(_Type), alignof(_Type)>::type
_M_storage;
};
@@ -195,6 +227,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*static_cast<_Storage*>(__ptr));
}
+ template<typename _Union>
+ constexpr decltype(auto) __get(in_place_index_t<0>, _Union&& __u)
+ { return std::forward<_Union>(__u)._M_first._M_get(); }
+
+ template<size_t _Np, typename _Union>
+ constexpr decltype(auto) __get(in_place_index_t<_Np>, _Union&& __u)
+ { return __get(in_place_index<_Np-1>, std::forward<_Union>(__u)._M_rest); }
+
+ // Returns the typed storage for __v.
+ template<size_t _Np, typename _Variant>
+ constexpr decltype(auto) __get(_Variant&& __v)
+ {
+ return __get(std::in_place_index<_Np>, std::forward<_Variant>(__v)._M_u);
+ }
+
// Various functions as "vtable" entries, where those vtables are used by
// polymorphic operations.
template<typename _Lhs, typename _Rhs>
@@ -202,13 +249,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__erased_ctor(void* __lhs, void* __rhs)
{ ::new (__lhs) decay_t<_Lhs>(__get_alternative<_Rhs>(__rhs)); }
- // TODO: Find a potential chance to reuse this accross the project.
- template<typename _Tp>
+ template<typename _Variant, size_t _Np>
constexpr void
- __erased_dtor(void* __ptr)
+ __erased_dtor(_Variant&& __v)
{
- using _Storage = decay_t<_Tp>;
- static_cast<_Storage*>(__ptr)->~_Storage();
+ auto&& __element = __get<_Np>(std::forward<_Variant>(__v));
+ using _Type = std::remove_reference_t<decltype(__element)>;
+ __element.~_Type();
}
template<typename _Lhs, typename _Rhs>
@@ -224,90 +271,108 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
swap(__get_alternative<_Lhs>(__lhs), __get_alternative<_Rhs>(__rhs));
}
- template<typename _Lhs, typename _Rhs>
+ template<typename _Variant, size_t _Np>
constexpr bool
- __erased_equal_to(void* __lhs, void* __rhs)
- { return __get_alternative<_Lhs>(__lhs) == __get_alternative<_Rhs>(__rhs); }
+ __erased_equal_to(_Variant&& __lhs, _Variant&& __rhs)
+ {
+ return __get<_Np>(std::forward<_Variant>(__lhs))
+ == __get<_Np>(std::forward<_Variant>(__rhs));
+ }
- template<typename _Lhs, typename _Rhs>
+ template<typename _Variant, size_t _Np>
constexpr bool
- __erased_less_than(void* __lhs, void* __rhs)
- { return __get_alternative<_Lhs>(__lhs) < __get_alternative<_Rhs>(__rhs); }
+ __erased_less_than(const _Variant& __lhs, const _Variant& __rhs)
+ {
+ return __get<_Np>(std::forward<_Variant>(__lhs))
+ < __get<_Np>(std::forward<_Variant>(__rhs));
+ }
template<typename _Tp>
constexpr size_t
__erased_hash(void* __t)
{ return std::hash<decay_t<_Tp>>{}(__get_alternative<_Tp>(__t)); }
+ // Defines members and ctors.
template<typename... _Types>
- struct _Variant_base;
+ union _Variadic_union { };
- template<typename... _Types>
- struct _Variant_storage
- { constexpr _Variant_storage() = default; };
-
- // Use recursive unions to implement a trivially destructible variant.
template<typename _First, typename... _Rest>
- struct _Variant_storage<_First, _Rest...>
+ union _Variadic_union<_First, _Rest...>
{
- constexpr _Variant_storage() = default;
+ constexpr _Variadic_union() : _M_rest() { }
+
+ template<typename... _Args>
+ constexpr _Variadic_union(in_place_index_t<0>, _Args&&... __args)
+ : _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
+ { }
+
+ template<size_t _Np, typename... _Args>
+ constexpr _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
+ : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
+ { }
+
+ _Uninitialized<_First> _M_first;
+ _Variadic_union<_Rest...> _M_rest;
+ };
+
+ // Defines index and the dtor, possibly trivial.
+ template<bool __trivially_destructible, typename... _Types>
+ struct _Variant_storage;
+
+ template<typename... _Types>
+ struct _Variant_storage<false, _Types...>
+ {
+ template<size_t... __indices>
+ static constexpr void (*_S_vtable[])(const _Variant_storage&) =
+ { &__erased_dtor<const _Variant_storage&, __indices>... };
+
+ constexpr _Variant_storage() : _M_index(variant_npos) { }
template<size_t _Np, typename... _Args>
constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
- : _M_union(in_place_index<_Np>, std::forward<_Args>(__args)...)
+ : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...),
+ _M_index(_Np)
{ }
- ~_Variant_storage() = default;
+ template<size_t... __indices>
+ constexpr void _M_destroy_impl(std::index_sequence<__indices...>)
+ {
+ if (_M_index != variant_npos)
+ _S_vtable<__indices...>[_M_index](*this);
+ }
- constexpr void*
- _M_storage() const
- {
- return const_cast<void*>(
- static_cast<const void*>(std::addressof(_M_union._M_first._M_storage)));
- }
+ ~_Variant_storage()
+ { _M_destroy_impl(std::make_index_sequence<sizeof...(_Types)>{}); }
- union _Union
- {
- constexpr _Union() {};
-
- template<typename... _Args>
- constexpr _Union(in_place_index_t<0>, _Args&&... __args)
- : _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
- { }
-
- template<size_t _Np, typename... _Args,
- typename = enable_if_t<0 < _Np && _Np < sizeof...(_Rest) + 1>>
- constexpr _Union(in_place_index_t<_Np>, _Args&&... __args)
- : _M_rest(in_place_index<_Np - 1>, std::forward<_Args>(__args)...)
- { }
-
- _Uninitialized<__storage<_First>> _M_first;
- _Variant_storage<_Rest...> _M_rest;
- } _M_union;
+ _Variadic_union<_Types...> _M_u;
+ size_t _M_index;
};
- template<typename _Derived, bool __is_trivially_destructible>
- struct _Dtor_mixin
+ template<typename... _Types>
+ struct _Variant_storage<true, _Types...>
{
- ~_Dtor_mixin()
- { static_cast<_Derived*>(this)->_M_destroy(); }
- };
+ constexpr _Variant_storage() : _M_index(variant_npos) { }
- template<typename _Derived>
- struct _Dtor_mixin<_Derived, true>
- {
- ~_Dtor_mixin() = default;
+ template<size_t _Np, typename... _Args>
+ constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
+ : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...),
+ _M_index(_Np)
+ { }
+
+ _Variadic_union<_Types...> _M_u;
+ size_t _M_index;
};
// Helps SFINAE on special member functions. Otherwise it can live in variant
// class.
template<typename... _Types>
struct _Variant_base :
- _Variant_storage<_Types...>,
- _Dtor_mixin<_Variant_base<_Types...>,
- __and_<std::is_trivially_destructible<_Types>...>::value>
+ _Variant_storage<(std::is_trivially_destructible_v<_Types> && ...),
+ _Types...>
{
- using _Storage = _Variant_storage<_Types...>;
+ using _Storage =
+ _Variant_storage<(std::is_trivially_destructible_v<_Types> && ...),
+ _Types...>;
constexpr
_Variant_base()
@@ -316,7 +381,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: _Variant_base(in_place_index<0>) { }
_Variant_base(const _Variant_base& __rhs)
- : _Storage(), _M_index(__rhs._M_index)
{
if (__rhs._M_valid())
{
@@ -324,31 +388,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ &__erased_ctor<__storage<_Types>&,
const __storage<_Types>&>... };
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+ this->_M_index = __rhs._M_index;
}
}
_Variant_base(_Variant_base&& __rhs)
noexcept(__and_<is_nothrow_move_constructible<_Types>...>::value)
- : _Storage(), _M_index(__rhs._M_index)
{
if (__rhs._M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
{ &__erased_ctor<__storage<_Types>&, __storage<_Types>&&>... };
_S_vtable[__rhs._M_index](_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)...), _M_index(_Np)
+ : _Storage(__i, std::forward<_Args>(__args)...)
{ }
_Variant_base&
operator=(const _Variant_base& __rhs)
{
- if (_M_index == __rhs._M_index)
+ if (this->_M_index == __rhs._M_index)
{
if (__rhs._M_valid())
{
@@ -368,11 +433,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
__catch (...)
{
- _M_index = variant_npos;
+ this->_M_index = variant_npos;
__throw_exception_again;
}
}
- __glibcxx_assert(_M_index == __rhs._M_index);
+ __glibcxx_assert(this->_M_index == __rhs._M_index);
return *this;
}
@@ -381,7 +446,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(__and_<is_nothrow_move_constructible<_Types>...,
is_nothrow_move_assignable<_Types>...>::value)
{
- if (_M_index == __rhs._M_index)
+ if (this->_M_index == __rhs._M_index)
{
if (__rhs._M_valid())
{
@@ -400,32 +465,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
__catch (...)
{
- _M_index = variant_npos;
+ this->_M_index = variant_npos;
__throw_exception_again;
}
}
return *this;
}
- void _M_destroy()
+ void*
+ _M_storage() const
{
- if (_M_valid())
- {
- static constexpr void (*_S_vtable[])(void*) =
- { &__erased_dtor<__storage<_Types>&>... };
- _S_vtable[this->_M_index](_M_storage());
- }
+ return const_cast<void*>(static_cast<const void*>(
+ std::addressof(_Storage::_M_u)));
}
- constexpr void*
- _M_storage() const
- { return _Storage::_M_storage(); }
-
constexpr bool
_M_valid() const noexcept
- { return _M_index != variant_npos; }
-
- size_t _M_index;
+ { return this->_M_index != variant_npos; }
};
// For how many times does _Tp appear in _Tuple?
@@ -490,15 +546,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void* __get_storage(_Variant&& __v)
{ return __v._M_storage(); }
- // Returns the reference to the desired alternative.
- // It is as unsafe as a reinterpret_cast.
- template<typename _Tp, typename _Variant>
- decltype(auto) __access(_Variant&& __v)
- {
- return __get_alternative<__reserved_type_map<_Variant&&, __storage<_Tp>>>(
- __get_storage(std::forward<_Variant>(__v)));
- }
-
// A helper used to create variadic number of _To types.
template<typename _From, typename _To>
using _To_type = _To;
@@ -598,9 +645,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_S_apply_all_alts(_Array_type& __vtable, index_sequence<__indices...>)
{ (_S_apply_single_alt<__indices>(__vtable._M_arr[__indices]), ...); }
- template<size_t __index>
+ template<size_t __index, typename T>
static constexpr void
- _S_apply_single_alt(auto& __element)
+ _S_apply_single_alt(T& __element)
{
using _Alternative = variant_alternative_t<__index, decay_t<_First>>;
using _Qualified_storage = __reserved_type_map<
@@ -656,23 +703,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<size_t _Np, typename... _Types>
- variant_alternative_t<_Np, variant<_Types...>>&
+ constexpr variant_alternative_t<_Np, variant<_Types...>>&
get(variant<_Types...>&);
template<size_t _Np, typename... _Types>
- variant_alternative_t<_Np, variant<_Types...>>&&
+ constexpr variant_alternative_t<_Np, variant<_Types...>>&&
get(variant<_Types...>&&);
template<size_t _Np, typename... _Types>
- variant_alternative_t<_Np, variant<_Types...>> const&
+ constexpr variant_alternative_t<_Np, variant<_Types...>> const&
get(const variant<_Types...>&);
template<size_t _Np, typename... _Types>
- variant_alternative_t<_Np, variant<_Types...>> const&&
+ constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
get(const variant<_Types...>&&);
template<typename _Tp, typename... _Types>
- inline _Tp& get(variant<_Types...>& __v)
+ constexpr inline _Tp& get(variant<_Types...>& __v)
{
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives");
@@ -681,7 +728,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Tp, typename... _Types>
- inline _Tp&& get(variant<_Types...>&& __v)
+ constexpr inline _Tp&& get(variant<_Types...>&& __v)
{
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives");
@@ -691,7 +738,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Tp, typename... _Types>
- inline const _Tp& get(const variant<_Types...>& __v)
+ constexpr inline const _Tp& get(const variant<_Types...>& __v)
{
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives");
@@ -700,7 +747,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Tp, typename... _Types>
- inline const _Tp&& get(const variant<_Types...>&& __v)
+ constexpr inline const _Tp&& get(const variant<_Types...>&& __v)
{
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives");
@@ -710,7 +757,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<size_t _Np, typename... _Types>
- inline add_pointer_t<variant_alternative_t<_Np, variant<_Types...>>>
+ constexpr inline
+ add_pointer_t<variant_alternative_t<_Np, variant<_Types...>>>
get_if(variant<_Types...>* __ptr) noexcept
{
using _Alternative_type = variant_alternative_t<_Np, variant<_Types...>>;
@@ -718,12 +766,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"The index should be in [0, number of alternatives)");
static_assert(!is_void_v<_Alternative_type>, "_Tp should not be void");
if (__ptr && __ptr->index() == _Np)
- return &__detail::__variant::__access<_Alternative_type>(*__ptr);
+ return &__detail::__variant::__get<_Np>(*__ptr);
return nullptr;
}
template<size_t _Np, typename... _Types>
- inline add_pointer_t<const variant_alternative_t<_Np, variant<_Types...>>>
+ constexpr inline
+ add_pointer_t<const variant_alternative_t<_Np, variant<_Types...>>>
get_if(const variant<_Types...>* __ptr) noexcept
{
using _Alternative_type = variant_alternative_t<_Np, variant<_Types...>>;
@@ -731,12 +780,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"The index should be in [0, number of alternatives)");
static_assert(!is_void_v<_Alternative_type>, "_Tp should not be void");
if (__ptr && __ptr->index() == _Np)
- return &__detail::__variant::__access<_Alternative_type>(*__ptr);
+ return &__detail::__variant::__get<_Np>(*__ptr);
return nullptr;
}
template<typename _Tp, typename... _Types>
- inline add_pointer_t<_Tp> get_if(variant<_Types...>* __ptr) noexcept
+ constexpr inline add_pointer_t<_Tp>
+ get_if(variant<_Types...>* __ptr) noexcept
{
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives");
@@ -745,7 +795,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Tp, typename... _Types>
- inline add_pointer_t<const _Tp> get_if(const variant<_Types...>* __ptr)
+ constexpr inline add_pointer_t<const _Tp>
+ get_if(const variant<_Types...>* __ptr)
noexcept
{
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
@@ -755,64 +806,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename... _Types>
- bool operator==(const variant<_Types...>& __lhs,
- const variant<_Types...>& __rhs)
+ constexpr bool operator==(const variant<_Types...>& __lhs,
+ const variant<_Types...>& __rhs)
{
- if (__lhs.index() != __rhs.index())
- return false;
-
- if (__lhs.valueless_by_exception())
- return true;
-
- using __detail::__variant::__storage;
- static constexpr bool (*_S_vtable[])(void*, void*) =
- { &__detail::__variant::__erased_equal_to<
- const __storage<_Types>&, const __storage<_Types>&>... };
- return _S_vtable[__lhs.index()](
- __detail::__variant::__get_storage(__lhs),
- __detail::__variant::__get_storage(__rhs));
+ return __lhs._M_equal_to(__rhs,
+ std::make_index_sequence<sizeof...(_Types)>{});
}
template<typename... _Types>
- inline bool
+ constexpr inline bool
operator!=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
{ return !(__lhs == __rhs); }
template<typename... _Types>
- inline bool
+ constexpr inline bool
operator<(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
{
- if (__lhs.index() < __rhs.index())
- return true;
-
- if (__lhs.index() > __rhs.index())
- return false;
-
- if (__lhs.valueless_by_exception())
- return false;
-
- using __detail::__variant::__storage;
- static constexpr bool (*_S_vtable[])(void*, void*) =
- { &__detail::__variant::__erased_less_than<
- const __storage<_Types>&,
- const __storage<_Types>&>... };
- return _S_vtable[__lhs.index()](
- __detail::__variant::__get_storage(__lhs),
- __detail::__variant::__get_storage(__rhs));
+ return __lhs._M_less_than(__rhs,
+ std::make_index_sequence<sizeof...(_Types)>{});
}
template<typename... _Types>
- inline bool
+ constexpr inline bool
operator>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
{ return __rhs < __lhs; }
template<typename... _Types>
- inline bool
+ constexpr inline bool
operator<=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
{ return !(__lhs > __rhs); }
template<typename... _Types>
- inline bool
+ constexpr inline bool
operator>=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
{ return !(__lhs < __rhs); }
@@ -1096,60 +1121,120 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
+ private:
+ template<size_t... __indices>
+ static constexpr bool
+ (*_S_equal_to_vtable[])(const variant&, const variant&) =
+ { &__detail::__variant::__erased_equal_to<
+ const variant&, __indices>... };
+
+ template<size_t... __indices>
+ static constexpr bool
+ (*_S_less_than_vtable[])(const variant&, const variant&) =
+ { &__detail::__variant::__erased_less_than<
+ const variant&, __indices>... };
+
+ template<size_t... __indices>
+ constexpr bool
+ _M_equal_to(const variant& __rhs,
+ std::index_sequence<__indices...>) const
+ {
+ if (this->index() != __rhs.index())
+ return false;
+
+ if (this->valueless_by_exception())
+ return true;
+
+ return _S_equal_to_vtable<__indices...>[this->index()](*this, __rhs);
+ }
+
+ template<size_t... __indices>
+ constexpr inline bool
+ _M_less_than(const variant& __rhs,
+ std::index_sequence<__indices...>) const
+ {
+ auto __lhs_index = this->index();
+ auto __rhs_index = __rhs.index();
+
+ if (__lhs_index < __rhs_index)
+ return true;
+
+ if (__lhs_index > __rhs_index)
+ return false;
+
+ if (this->valueless_by_exception())
+ return false;
+
+ return _S_less_than_vtable<__indices...>[__lhs_index](*this, __rhs);
+ }
+
+ template<size_t _Np, typename _Vp>
+ friend constexpr decltype(auto) __detail::__variant::
+#if _GLIBCXX_INLINE_VERSION
+ __7:: // Required due to PR c++/59256
+#endif
+ __get(_Vp&& __v);
+
template<typename _Vp>
friend void* __detail::__variant::
#if _GLIBCXX_INLINE_VERSION
__7:: // Required due to PR c++/59256
#endif
__get_storage(_Vp&& __v);
+
+ template<typename... _Tp>
+ friend constexpr bool
+ operator==(const variant<_Tp...>& __lhs,
+ const variant<_Tp...>& __rhs);
+
+ template<typename... _Tp>
+ friend constexpr bool
+ operator<(const variant<_Tp...>& __lhs,
+ const variant<_Tp...>& __rhs);
};
template<size_t _Np, typename... _Types>
- variant_alternative_t<_Np, variant<_Types...>>&
+ constexpr variant_alternative_t<_Np, variant<_Types...>>&
get(variant<_Types...>& __v)
{
static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)");
if (__v.index() != _Np)
__throw_bad_variant_access("Unexpected index");
- return __detail::__variant::__access<
- variant_alternative_t<_Np, variant<_Types...>>>(__v);
+ return __detail::__variant::__get<_Np>(__v);
}
template<size_t _Np, typename... _Types>
- variant_alternative_t<_Np, variant<_Types...>>&&
+ constexpr variant_alternative_t<_Np, variant<_Types...>>&&
get(variant<_Types...>&& __v)
{
static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)");
if (__v.index() != _Np)
__throw_bad_variant_access("Unexpected index");
- return __detail::__variant::__access<
- variant_alternative_t<_Np, variant<_Types...>>>(std::move(__v));
+ return __detail::__variant::__get<_Np>(std::move(__v));
}
template<size_t _Np, typename... _Types>
- const variant_alternative_t<_Np, variant<_Types...>>&
+ constexpr const variant_alternative_t<_Np, variant<_Types...>>&
get(const variant<_Types...>& __v)
{
static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)");
if (__v.index() != _Np)
__throw_bad_variant_access("Unexpected index");
- return __detail::__variant::__access<
- variant_alternative_t<_Np, variant<_Types...>>>(__v);
+ return __detail::__variant::__get<_Np>(__v);
}
template<size_t _Np, typename... _Types>
- const variant_alternative_t<_Np, variant<_Types...>>&&
+ constexpr const variant_alternative_t<_Np, variant<_Types...>>&&
get(const variant<_Types...>&& __v)
{
static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)");
if (__v.index() != _Np)
__throw_bad_variant_access("Unexpected index");
- return __detail::__variant::__access<
- variant_alternative_t<_Np, variant<_Types...>>>(std::move(__v));
+ return __detail::__variant::__get<_Np>(std::move(__v));
}
template<typename _Visitor, typename... _Variants>
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index 5bd4e70..54acc93 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -51,6 +51,14 @@ struct DefaultNoexcept
DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default;
};
+struct nonliteral
+{
+ nonliteral() { }
+
+ bool operator<(const nonliteral&) const;
+ bool operator==(const nonliteral&) const;
+};
+
void default_ctor()
{
static_assert(is_default_constructible_v<variant<int, string>>, "");
@@ -175,22 +183,40 @@ void test_get()
void test_relational()
{
{
- const variant<int, string> a, b;
- (void)(a < b);
- (void)(a > b);
- (void)(a <= b);
- (void)(a == b);
- (void)(a != b);
- (void)(a >= b);
+ constexpr variant<int, nonliteral> a(42), b(43);
+ static_assert((a < b), "");
+ static_assert(!(a > b), "");
+ static_assert((a <= b), "");
+ static_assert(!(a == b), "");
+ static_assert((a != b), "");
+ static_assert(!(a >= b), "");
}
{
- const monostate a, b;
- (void)(a < b);
- (void)(a > b);
- (void)(a <= b);
- (void)(a == b);
- (void)(a != b);
- (void)(a >= b);
+ constexpr variant<int, nonliteral> a(42), b(42);
+ static_assert(!(a < b), "");
+ static_assert(!(a > b), "");
+ static_assert((a <= b), "");
+ static_assert((a == b), "");
+ static_assert(!(a != b), "");
+ static_assert((a >= b), "");
+ }
+ {
+ constexpr variant<int, nonliteral> a(43), b(42);
+ static_assert(!(a < b), "");
+ static_assert((a > b), "");
+ static_assert(!(a <= b), "");
+ static_assert(!(a == b), "");
+ static_assert((a != b), "");
+ static_assert((a >= b), "");
+ }
+ {
+ constexpr monostate a, b;
+ static_assert(!(a < b), "");
+ static_assert(!(a > b), "");
+ static_assert((a <= b), "");
+ static_assert((a == b), "");
+ static_assert(!(a != b), "");
+ static_assert((a >= b), "");
}
}
@@ -247,14 +273,59 @@ void test_constexpr()
constexpr literal() = default;
};
- struct nonliteral {
- nonliteral() { }
- };
-
constexpr variant<literal, nonliteral> v{};
constexpr variant<literal, nonliteral> v1{in_place_type<literal>};
constexpr variant<literal, nonliteral> v2{in_place_index<0>};
}
+
+ {
+ constexpr variant<int> a(42);
+ static_assert(get<0>(a) == 42, "");
+ }
+ {
+ constexpr variant<int, nonliteral> a(42);
+ static_assert(get<0>(a) == 42, "");
+ }
+ {
+ constexpr variant<nonliteral, int> a(42);
+ static_assert(get<1>(a) == 42, "");
+ }
+ {
+ constexpr variant<int> a(42);
+ static_assert(get<int>(a) == 42, "");
+ }
+ {
+ constexpr variant<int, nonliteral> a(42);
+ static_assert(get<int>(a) == 42, "");
+ }
+ {
+ constexpr variant<nonliteral, int> a(42);
+ static_assert(get<int>(a) == 42, "");
+ }
+ {
+ constexpr variant<int> a(42);
+ static_assert(get<0>(std::move(a)) == 42, "");
+ }
+ {
+ constexpr variant<int, nonliteral> a(42);
+ static_assert(get<0>(std::move(a)) == 42, "");
+ }
+ {
+ constexpr variant<nonliteral, int> a(42);
+ static_assert(get<1>(std::move(a)) == 42, "");
+ }
+ {
+ constexpr variant<int> a(42);
+ static_assert(get<int>(std::move(a)) == 42, "");
+ }
+ {
+ constexpr variant<int, nonliteral> a(42);
+ static_assert(get<int>(std::move(a)) == 42, "");
+ }
+ {
+ constexpr variant<nonliteral, int> a(42);
+ static_assert(get<int>(std::move(a)) == 42, "");
+ }
}
void test_pr77641()
commit e80deb97ce75f6a3057c1115c4511fa3dbfb08d9
Author: Tim Shen <timshen@google.com>
Date: Thu Nov 24 13:35:00 2016 -0800
2016-11-27 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.
diff --git a/libstdc++-v3/include/bits/enable_special_members.h b/libstdc++-v3/include/bits/enable_special_members.h
index 07c6c99..4f4477b 100644
--- a/libstdc++-v3/include/bits/enable_special_members.h
+++ b/libstdc++-v3/include/bits/enable_special_members.h
@@ -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>
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index a913074..7cc7402 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -335,14 +335,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::make_index_sequence<sizeof...(_Types)>{});
+ _M_index = variant_npos;
+ }
+
~_Variant_storage()
- { _M_destroy_impl(std::make_index_sequence<sizeof...(_Types)>{}); }
+ { _M_reset(); }
_Variadic_union<_Types...> _M_u;
size_t _M_index;
@@ -359,6 +365,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_index(_Np)
{ }
+ void _M_reset()
+ { _M_index = variant_npos; }
+
_Variadic_union<_Types...> _M_u;
size_t _M_index;
};
@@ -441,6 +450,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>...,
@@ -458,16 +481,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;
}
@@ -687,6 +701,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
@@ -865,8 +890,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return false; }
template<typename... _Types>
- inline auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
- noexcept(noexcept(__lhs.swap(__rhs))) -> decltype(__lhs.swap(__rhs))
+ 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); }
class bad_variant_access : public exception
@@ -1028,25 +1055,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 +1093,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 +1122,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 +1137,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 +1285,16 @@ _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::make_index_sequence<sizeof...(_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((noexcept(hash<decay_t<_Types>>{}(std::declval<_Types>()))
+ && ...))
{
if (!__t.valueless_by_exception())
{
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index 54acc93..b973143 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -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() { }
@@ -222,9 +231,9 @@ void test_relational()
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()
@@ -370,7 +379,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>, "");
@@ -378,3 +388,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), "");
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/hash.cc b/libstdc++-v3/testsuite/20_util/variant/hash.cc
index 38991ae..64d053f 100644
--- a/libstdc++-v3/testsuite/20_util/variant/hash.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/hash.cc
@@ -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()
{
commit 1503eff1772d0ad7638dad2507d860ea56039714
Author: Tim Shen <timshen@google.com>
Date: Sat Nov 26 20:10:40 2016 -0800
2016-11-27 Tim Shen <timshen@google.com>
* include/std/variant (visit): Make visit constexpr. Also cleanup
__get_alternative and __storage, since we don't support reference/void
alternatives any more.
* testsuite/20_util/variant/compile.cc: Add tests.
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 7cc7402..1159772 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -42,10 +42,33 @@
#include <bits/move.h>
#include <bits/uses_allocator.h>
#include <bits/functional_hash.h>
+#include <bits/invoke.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace __detail
+{
+namespace __variant
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ template<size_t _Np, typename... _Types>
+ struct _Nth_type;
+
+ template<size_t _Np, typename _First, typename... _Rest>
+ struct _Nth_type<_Np, _First, _Rest...>
+ : _Nth_type<_Np-1, _Rest...> { };
+
+ template<typename _First, typename... _Rest>
+ struct _Nth_type<0, _First, _Rest...>
+ { using type = _First; };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace __variant
+} // namespace __detail
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Types> class tuple;
template<typename... _Types> class variant;
@@ -99,6 +122,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr size_t variant_npos = -1;
+ template<size_t _Np, typename... _Types>
+ constexpr variant_alternative_t<_Np, variant<_Types...>>&
+ get(variant<_Types...>&);
+
+ template<size_t _Np, typename... _Types>
+ constexpr variant_alternative_t<_Np, variant<_Types...>>&&
+ get(variant<_Types...>&&);
+
+ template<size_t _Np, typename... _Types>
+ constexpr variant_alternative_t<_Np, variant<_Types...>> const&
+ get(const variant<_Types...>&);
+
+ template<size_t _Np, typename... _Types>
+ constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
+ get(const variant<_Types...>&&);
+
_GLIBCXX_END_NAMESPACE_VERSION
namespace __detail
@@ -119,41 +158,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::integral_constant<size_t, is_same_v<_Tp, _First>
? 0 : __index_of_v<_Tp, _Rest...> + 1> {};
- // Extract _From's qualifiers and references and apply it to _To.
- // __reserved_type_map<const int&, char> is const char&.
- template<typename _From, typename _To>
- struct __reserved_type_map_impl
- { using type = _To; };
-
- template<typename _From, typename _To>
- using __reserved_type_map =
- typename __reserved_type_map_impl<_From, _To>::type;
-
- template<typename _From, typename _To>
- struct __reserved_type_map_impl<_From&, _To>
- { using type = add_lvalue_reference_t<__reserved_type_map<_From, _To>>; };
-
- template<typename _From, typename _To>
- struct __reserved_type_map_impl<_From&&, _To>
- { using type = add_rvalue_reference_t<__reserved_type_map<_From, _To>>; };
-
- template<typename _From, typename _To>
- struct __reserved_type_map_impl<const _From, _To>
- { using type = add_const_t<__reserved_type_map<_From, _To>>; };
-
- template<typename _From, typename _To>
- struct __reserved_type_map_impl<volatile _From, _To>
- { using type = add_volatile_t<__reserved_type_map<_From, _To>>; };
-
- template<typename _From, typename _To>
- struct __reserved_type_map_impl<const volatile _From, _To>
- { using type = add_cv_t<__reserved_type_map<_From, _To>>; };
-
- // This abstraction might be useful for future features,
- // e.g. boost::recursive_wrapper.
- template<typename _Alternative>
- using __storage = _Alternative;
-
// _Uninitialized nullify the destructor calls.
// This is necessary, since we define _Variadic_union as a recursive union,
// and we don't want to inspect the union members one by one in its dtor,
@@ -215,16 +219,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_storage;
};
- // Given a qualified storage type, return the desired reference.
- // For example, variant<int>&& stores the int as __storage<int>, and
- // _Qualified_storage will be __storage<int>&&.
- template<typename _Qualified_storage>
- decltype(auto)
- __get_alternative(void* __ptr)
+ template<typename _Ref>
+ _Ref __ref_cast(void* __ptr)
{
- using _Storage = decay_t<_Qualified_storage>;
- return __reserved_type_map<_Qualified_storage, _Storage>(
- *static_cast<_Storage*>(__ptr));
+ return static_cast<_Ref>(*static_cast<remove_reference_t<_Ref>*>(__ptr));
}
template<typename _Union>
@@ -247,7 +245,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Lhs, typename _Rhs>
constexpr void
__erased_ctor(void* __lhs, void* __rhs)
- { ::new (__lhs) decay_t<_Lhs>(__get_alternative<_Rhs>(__rhs)); }
+ { ::new (__lhs) remove_reference_t<_Lhs>(__ref_cast<_Rhs>(__rhs)); }
template<typename _Variant, size_t _Np>
constexpr void
@@ -261,14 +259,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Lhs, typename _Rhs>
constexpr void
__erased_assign(void* __lhs, void* __rhs)
- { __get_alternative<_Lhs>(__lhs) = __get_alternative<_Rhs>(__rhs); }
+ { __ref_cast<_Lhs>(__lhs) = __ref_cast<_Rhs>(__rhs); }
template<typename _Lhs, typename _Rhs>
constexpr void
__erased_swap(void* __lhs, void* __rhs)
{
using std::swap;
- swap(__get_alternative<_Lhs>(__lhs), __get_alternative<_Rhs>(__rhs));
+ swap(__ref_cast<_Lhs>(__lhs), __ref_cast<_Rhs>(__rhs));
}
template<typename _Variant, size_t _Np>
@@ -290,7 +288,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp>
constexpr size_t
__erased_hash(void* __t)
- { return std::hash<decay_t<_Tp>>{}(__get_alternative<_Tp>(__t)); }
+ {
+ return std::hash<remove_cv_t<remove_reference_t<_Tp>>>{}(
+ __ref_cast<_Tp>(__t));
+ }
// Defines members and ctors.
template<typename... _Types>
@@ -394,8 +395,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__rhs._M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
- { &__erased_ctor<__storage<_Types>&,
- const __storage<_Types>&>... };
+ { &__erased_ctor<_Types&, const _Types&>... };
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
this->_M_index = __rhs._M_index;
}
@@ -407,7 +407,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__rhs._M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
- { &__erased_ctor<__storage<_Types>&, __storage<_Types>&&>... };
+ { &__erased_ctor<_Types&, _Types&&>... };
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
this->_M_index = __rhs._M_index;
}
@@ -427,8 +427,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__rhs._M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
- { &__erased_assign<__storage<_Types>&,
- const __storage<_Types>&>... };
+ { &__erased_assign<_Types&, const _Types&>... };
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
}
}
@@ -474,8 +473,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__rhs._M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
- { &__erased_assign<__storage<_Types>&,
- __storage<_Types>&&>... };
+ { &__erased_assign<_Types&, _Types&&>... };
_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
}
}
@@ -560,20 +558,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void* __get_storage(_Variant&& __v)
{ return __v._M_storage(); }
- // A helper used to create variadic number of _To types.
- template<typename _From, typename _To>
- using _To_type = _To;
-
- // Call the actual visitor.
- // _Args are qualified storage types.
- template<typename _Visitor, typename... _Args>
- decltype(auto)
- __visit_invoke(_Visitor&& __visitor, _To_type<_Args, void*>... __ptrs)
- {
- return std::forward<_Visitor>(__visitor)(
- __get_alternative<_Args>(__ptrs)...);
- }
-
// Used for storing multi-dimensional vtable.
template<typename _Tp, size_t... _Dimensions>
struct _Multi_array
@@ -597,107 +581,112 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
};
// Creates a multi-dimensional vtable recursively.
- // _Variant_tuple is initially the input from visit(), and gets gradually
- // consumed.
- // _Arg_tuple is enumerated alternative sequence, represented by a
- // qualified storage.
//
// For example,
// visit([](auto, auto){},
- // variant<int, char>(),
- // variant<float, double, long double>())
+ // variant<int, char>(), // typedef'ed as V1
+ // variant<float, double, long double>()) // typedef'ed as V2
// will trigger instantiations of:
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*), 2, 3>,
- // tuple<variant<int, char>,
- // variant<float, double, long double>>,
- // tuple<>>
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*), 3>,
- // tuple<variant<float, double, long double>>,
- // tuple<int>>
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
- // tuple<>,
- // tuple<int, float>>
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
- // tuple<>,
- // tuple<int, double>>
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
- // tuple<>,
- // tuple<int, long double>>
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*), 3>,
- // tuple<variant<float, double, long double>>,
- // tuple<char>>
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
- // tuple<>,
- // tuple<char, float>>
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
- // tuple<>,
- // tuple<char, double>>
- // __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
- // tuple<>,
- // tuple<char, long double>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 2, 3>,
+ // tuple<V1&&, V2&&>, std::index_sequence<>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>,
+ // tuple<V1&&, V2&&>, std::index_sequence<0>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+ // tuple<V1&&, V2&&>, std::index_sequence<0, 0>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+ // tuple<V1&&, V2&&>, std::index_sequence<0, 1>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+ // tuple<V1&&, V2&&>, std::index_sequence<0, 2>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>,
+ // tuple<V1&&, V2&&>, std::index_sequence<1>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+ // tuple<V1&&, V2&&>, std::index_sequence<1, 0>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+ // tuple<V1&&, V2&&>, std::index_sequence<1, 1>>
+ // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+ // tuple<V1&&, V2&&>, std::index_sequence<1, 2>>
// The returned multi-dimensional vtable can be fast accessed by the visitor
// using index calculation.
- template<typename _Array_type, typename _Variant_tuple, typename _Arg_tuple>
+ template<typename _Array_type, typename _Variant_tuple, typename _Index_seq>
struct __gen_vtable_impl;
- template<typename _Array_type, typename _First, typename... _Rest,
- typename... _Args>
- struct __gen_vtable_impl<_Array_type, tuple<_First, _Rest...>,
- tuple<_Args...>>
+ template<typename _Result_type, typename _Visitor, size_t... __unused,
+ typename... _Variants, size_t... __indices>
+ struct __gen_vtable_impl<
+ _Multi_array<_Result_type (*)(_Visitor, _Variants...), __unused...>,
+ tuple<_Variants...>, std::index_sequence<__indices...>>
{
+ using _Next =
+ remove_reference_t<typename _Nth_type<sizeof...(__indices),
+ _Variants...>::type>;
+ using _Array_type =
+ _Multi_array<_Result_type (*)(_Visitor, _Variants...), __unused...>;
+
static constexpr _Array_type
_S_apply()
{
_Array_type __vtable{};
_S_apply_all_alts(
- __vtable, make_index_sequence<variant_size_v<decay_t<_First>>>());
+ __vtable, make_index_sequence<variant_size_v<_Next>>());
return __vtable;
}
- template<size_t... __indices>
+ template<size_t... __var_indices>
static constexpr void
- _S_apply_all_alts(_Array_type& __vtable, index_sequence<__indices...>)
- { (_S_apply_single_alt<__indices>(__vtable._M_arr[__indices]), ...); }
+ _S_apply_all_alts(_Array_type& __vtable,
+ std::index_sequence<__var_indices...>)
+ {
+ (_S_apply_single_alt<__var_indices>(
+ __vtable._M_arr[__var_indices]), ...);
+ }
template<size_t __index, typename T>
static constexpr void
_S_apply_single_alt(T& __element)
{
- using _Alternative = variant_alternative_t<__index, decay_t<_First>>;
- using _Qualified_storage = __reserved_type_map<
- _First, __storage<_Alternative>>;
+ using _Alternative = variant_alternative_t<__index, _Next>;
__element = __gen_vtable_impl<
- decay_t<decltype(__element)>, tuple<_Rest...>,
- tuple<_Args..., _Qualified_storage>>::_S_apply();
+ remove_reference_t<
+ decltype(__element)>, tuple<_Variants...>,
+ std::index_sequence<__indices..., __index>>::_S_apply();
}
};
- template<typename _Result_type, typename _Visitor, typename... _Args>
+ template<typename _Result_type, typename _Visitor, typename... _Variants,
+ size_t... __indices>
struct __gen_vtable_impl<
- _Multi_array<_Result_type (*)(_Visitor, _To_type<_Args, void*>...)>,
- tuple<>, tuple<_Args...>>
+ _Multi_array<_Result_type (*)(_Visitor, _Variants...)>,
+ tuple<_Variants...>, std::index_sequence<__indices...>>
{
using _Array_type =
- _Multi_array<_Result_type (*)(_Visitor&&, _To_type<_Args, void*>...)>;
+ _Multi_array<_Result_type (*)(_Visitor&&, _Variants...)>;
+
+ decltype(auto)
+ static constexpr __visit_invoke(_Visitor&& __visitor, _Variants... __vars)
+ {
+ return __invoke(std::forward<_Visitor>(__visitor),
+ std::get<__indices>(
+ std::forward<_Variants>(__vars))...);
+ }
static constexpr auto
_S_apply()
- { return _Array_type{&__visit_invoke<_Visitor, _Args...>}; }
+ { return _Array_type{&__visit_invoke}; }
};
template<typename _Result_type, typename _Visitor, typename... _Variants>
struct __gen_vtable
{
- using _Func_ptr =
- _Result_type (*)(_Visitor&&, _To_type<_Variants, void*>...);
+ using _Func_ptr = _Result_type (*)(_Visitor&&, _Variants...);
using _Array_type =
- _Multi_array<_Func_ptr, variant_size_v<decay_t<_Variants>>...>;
+ _Multi_array<_Func_ptr,
+ variant_size_v<remove_reference_t<_Variants>>...>;
static constexpr _Array_type
_S_apply()
{
- return __gen_vtable_impl<
- _Array_type, tuple<_Variants...>, tuple<>>::_S_apply();
+ return __gen_vtable_impl<_Array_type, tuple<_Variants...>,
+ std::index_sequence<>>::_S_apply();
}
};
@@ -727,22 +716,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __v.index() == __detail::__variant::__index_of_v<_Tp, _Types...>;
}
- template<size_t _Np, typename... _Types>
- constexpr variant_alternative_t<_Np, variant<_Types...>>&
- get(variant<_Types...>&);
-
- template<size_t _Np, typename... _Types>
- constexpr variant_alternative_t<_Np, variant<_Types...>>&&
- get(variant<_Types...>&&);
-
- template<size_t _Np, typename... _Types>
- constexpr variant_alternative_t<_Np, variant<_Types...>> const&
- get(const variant<_Types...>&);
-
- template<size_t _Np, typename... _Types>
- constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
- get(const variant<_Types...>&&);
-
template<typename _Tp, typename... _Types>
constexpr inline _Tp& get(variant<_Types...>& __v)
{
@@ -867,7 +840,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return !(__lhs < __rhs); }
template<typename _Visitor, typename... _Variants>
- decltype(auto) visit(_Visitor&&, _Variants&&...);
+ constexpr decltype(auto) visit(_Visitor&&, _Variants&&...);
struct monostate { };
@@ -967,9 +940,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using __accepted_type = __to_type<__accepted_index<_Tp>>;
template<typename _Tp>
- using __storage = __detail::__variant::__storage<_Tp>;
-
- template<typename _Tp>
static constexpr size_t __index_of =
__detail::__variant::__index_of_v<_Tp, _Types...>;
@@ -1129,8 +1099,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (this->_M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
- { &__detail::__variant::__erased_swap<
- __storage<_Types>&, __storage<_Types>&>... };
+ { &__detail::__variant::__erased_swap<_Types&, _Types&>... };
_S_vtable[__rhs._M_index](this->_M_storage(),
__rhs._M_storage());
}
@@ -1270,17 +1239,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Visitor, typename... _Variants>
- decltype(auto)
+ constexpr decltype(auto)
visit(_Visitor&& __visitor, _Variants&&... __variants)
{
+ if ((__variants.valueless_by_exception() || ...))
+ __throw_bad_variant_access("Unexpected index");
+
using _Result_type =
decltype(std::forward<_Visitor>(__visitor)(get<0>(__variants)...));
- static constexpr auto _S_vtable =
+ constexpr auto _S_vtable =
__detail::__variant::__gen_vtable<
_Result_type, _Visitor&&, _Variants&&...>::_S_apply();
auto __func_ptr = _S_vtable._M_access(__variants.index()...);
return (*__func_ptr)(std::forward<_Visitor>(__visitor),
- __detail::__variant::__get_storage(__variants)...);
+ std::forward<_Variants>(__variants)...);
}
template<typename... _Types>
@@ -1300,7 +1272,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
namespace __edv = __detail::__variant;
static constexpr size_t (*_S_vtable[])(void*) =
- { &__edv::__erased_hash<const __edv::__storage<_Types>&>... };
+ { &__edv::__erased_hash<const _Types&>... };
return hash<size_t>{}(__t.index())
+ _S_vtable[__t.index()](__edv::__get_storage(__t));
}
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index b973143..8f77ffb 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -260,6 +260,22 @@ void test_visit()
};
visit(Visitor(), variant<int, char>(), variant<float, double>());
}
+ {
+ struct Visitor
+ {
+ constexpr bool operator()(const int&) { return true; }
+ constexpr bool operator()(const nonliteral&) { return false; }
+ };
+ static_assert(visit(Visitor(), variant<int, nonliteral>(0)), "");
+ }
+ {
+ struct Visitor
+ {
+ constexpr bool operator()(const int&) { return true; }
+ constexpr bool operator()(const nonliteral&) { return false; }
+ };
+ static_assert(visit(Visitor(), variant<int, nonliteral>(0)), "");
+ }
}
void test_constexpr()