* [Patches] Add variant constexpr support for visit, comparisons and get
@ 2016-11-27 5:38 Tim Shen
2016-11-30 16:27 ` Jonathan Wakely
0 siblings, 1 reply; 10+ messages in thread
From: Tim Shen @ 2016-11-27 5:38 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 710 bytes --]
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
[-- Attachment #2: a.diff --]
[-- Type: text/x-patch, Size: 10514 bytes --]
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();
[-- Attachment #3: b.diff --]
[-- Type: text/x-patch, Size: 28546 bytes --]
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()
[-- Attachment #4: c.diff --]
[-- Type: text/x-patch, Size: 10854 bytes --]
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()
{
[-- Attachment #5: d.diff --]
[-- Type: text/x-patch, Size: 19759 bytes --]
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()
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-11-27 5:38 [Patches] Add variant constexpr support for visit, comparisons and get Tim Shen
@ 2016-11-30 16:27 ` Jonathan Wakely
2016-12-01 3:29 ` Tim Shen
2016-12-03 3:15 ` Tim Shen
0 siblings, 2 replies; 10+ messages in thread
From: Jonathan Wakely @ 2016-11-30 16:27 UTC (permalink / raw)
To: Tim Shen; +Cc: libstdc++, gcc-patches
On 26/11/16 21:38 -0800, Tim Shen wrote:
>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.
Yay! less code.
>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.
Great stuff.
> * 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 wording confused me slightly. How about:
"_Uninitialized makes destructors trivial"
>+ // 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.
Please change "it's slow" to "that's slow".
>+ template<typename _Type, bool = std::is_literal_type_v<_Type>>
> struct _Uninitialized;
I'm still unsure that is_literal_type is the right trait here. If it's
definitely right then we should probably *not* deprecate it in C++17!
> 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;
I think this could use __aligned_membuf, which would reduce the
alignment requirements for some types (e.g. long long on x86-32).
That would also mean you get the _M_ptr() member so don't need all the
casts.
>+ ~_Variant_storage()
>+ { _M_destroy_impl(std::make_index_sequence<sizeof...(_Types)>{}); }
You can use index_sequence_for<_Types...> here.
>@@ -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>
This needs to be _Tp not T
>+ return __lhs._M_equal_to(__rhs,
>+ std::make_index_sequence<sizeof...(_Types)>{});
Another one that could use index_sequence_for<_Types...>
>+ return __lhs._M_less_than(__rhs,
>+ std::make_index_sequence<sizeof...(_Types)>{});
Same again.
> * 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
>@@ -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) { }
> };
>
>+ 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(); }
These can also use index_sequence_for<_Types...>
>@@ -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)>>
And again.
> {
> 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>()))
>+ && ...))
This could be
__and_<is_nothrow_callable<hash<decay_t<_Types>>(_Types)>...>
but I'm not sure it would be an improvement. The is_callable check is
expensive, but maybe we need it anyway to correctly disable this
function if the hash specialization should be posisoned?
>@@ -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 =
If this isn't static now it could be called simply __vtable, the _S_
prefix is misleading. How many of these _S_vtable variables actually
need to be static? If they're all trivial types and constexpr then it
probably doesn't matter either way, there shouldn't be any difference.
> __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)...);
> }
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-11-30 16:27 ` Jonathan Wakely
@ 2016-12-01 3:29 ` Tim Shen
2016-12-01 11:16 ` Jonathan Wakely
2016-12-03 3:15 ` Tim Shen
1 sibling, 1 reply; 10+ messages in thread
From: Tim Shen @ 2016-12-01 3:29 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches
On Wed, Nov 30, 2016 at 8:27 AM, Jonathan Wakely wrote:
> On 26/11/16 21:38 -0800, Tim Shen wrote:
>> + template<typename _Type, bool = std::is_literal_type_v<_Type>>
>> struct _Uninitialized;
>
>
> I'm still unsure that is_literal_type is the right trait here. If it's
> definitely right then we should probably *not* deprecate it in C++17!
No it's not right. We need this only because [basic.types]p10.5.3 (in n4606):
if it (a literal type) is a union, at least one of its non-static
data members is of non-volatile literal type, ...
is not implemented. In the current GCC implementation, however, all
non-static data members need to be literal types, in order to create a
literal union.
With the current GCC implementation, to keep our goal, which is to
make _Variadic_union literal type, we need to ensure that
_Uninitialized<T> is literal type, by specializing on T:
1) If is_literal_type_v<T>, store a T;
2) otherwise, store a raw buffer of T.
In the future, when [basic.types]p10.5.3 is implemented, we don't need
is_literal_type_v.
I'll add a comment here.
I didn't check for other compilers.
--
Regards,
Tim Shen
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-12-01 3:29 ` Tim Shen
@ 2016-12-01 11:16 ` Jonathan Wakely
0 siblings, 0 replies; 10+ messages in thread
From: Jonathan Wakely @ 2016-12-01 11:16 UTC (permalink / raw)
To: Tim Shen; +Cc: libstdc++, gcc-patches
On 30/11/16 19:29 -0800, Tim Shen wrote:
>On Wed, Nov 30, 2016 at 8:27 AM, Jonathan Wakely wrote:
>> On 26/11/16 21:38 -0800, Tim Shen wrote:
>>> + template<typename _Type, bool = std::is_literal_type_v<_Type>>
>>> struct _Uninitialized;
>>
>>
>> I'm still unsure that is_literal_type is the right trait here. If it's
>> definitely right then we should probably *not* deprecate it in C++17!
>
>No it's not right. We need this only because [basic.types]p10.5.3 (in n4606):
>
> if it (a literal type) is a union, at least one of its non-static
>data members is of non-volatile literal type, ...
>
>is not implemented. In the current GCC implementation, however, all
>non-static data members need to be literal types, in order to create a
>literal union.
>
>With the current GCC implementation, to keep our goal, which is to
>make _Variadic_union literal type, we need to ensure that
>_Uninitialized<T> is literal type, by specializing on T:
>1) If is_literal_type_v<T>, store a T;
>2) otherwise, store a raw buffer of T.
>
>In the future, when [basic.types]p10.5.3 is implemented, we don't need
>is_literal_type_v.
>
>I'll add a comment here.
Thanks, that will stop me asking again and again in future ;-)
I think we want to get [basic.types] p10 implemented before we declare
C++17 support non-experimental, so we don't have to change
std::variant layout later.
>I didn't check for other compilers.
That's fine, the current approach should work for them too.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-11-30 16:27 ` Jonathan Wakely
2016-12-01 3:29 ` Tim Shen
@ 2016-12-03 3:15 ` Tim Shen
2016-12-06 10:30 ` Jonathan Wakely
1 sibling, 1 reply; 10+ messages in thread
From: Tim Shen @ 2016-12-03 3:15 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 6799 bytes --]
On Wed, Nov 30, 2016 at 8:27 AM, Jonathan Wakely wrote:
> On 26/11/16 21:38 -0800, Tim Shen wrote:
>>
>> 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.
>
>
> Yay! less code.
Yay! Also removed the unused #include.
>
>> - template<typename _Type, bool __is_literal =
>> std::is_literal_type_v<_Type>>
>> + // _Uninitialized nullify the destructor calls.
>
>
> This wording confused me slightly. How about:
>
> "_Uninitialized makes destructors trivial"
Change this section of comment to the discussed content.
>
>> + // 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.
>
>
> Please change "it's slow" to "that's slow".
N/A.
>
>> + template<typename _Type, bool = std::is_literal_type_v<_Type>>
>> struct _Uninitialized;
>
>
> I'm still unsure that is_literal_type is the right trait here. If it's
> definitely right then we should probably *not* deprecate it in C++17!
Already discussed.
>
>> 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;
>
>
> I think this could use __aligned_membuf, which would reduce the
> alignment requirements for some types (e.g. long long on x86-32).
Done.
>
> That would also mean you get the _M_ptr() member so don't need all the
> casts.
>
>> + ~_Variant_storage()
>> + { _M_destroy_impl(std::make_index_sequence<sizeof...(_Types)>{}); }
>
>
> You can use index_sequence_for<_Types...> here.
Done
>
>> @@ -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>
>
>
> This needs to be _Tp not T
Done.
>
>> + return __lhs._M_equal_to(__rhs,
>> +
>> std::make_index_sequence<sizeof...(_Types)>{});
>
>
> Another one that could use index_sequence_for<_Types...>
Done.
>
>> + return __lhs._M_less_than(__rhs,
>> +
>> std::make_index_sequence<sizeof...(_Types)>{});
>
>
> Same again.
Same again. ;)
>
>
>> * 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
>> @@ -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) { }
>> };
>>
>> + 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(); }
>
>
> These can also use index_sequence_for<_Types...>
Done.
>
>> @@ -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)>>
>
>
> And again.
And again.
>
>> {
>> 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>()))
>> + && ...))
>
>
> This could be
> __and_<is_nothrow_callable<hash<decay_t<_Types>>(_Types)>...>
> but I'm not sure it would be an improvement. The is_callable check is
> expensive, but maybe we need it anyway to correctly disable this
> function if the hash specialization should be posisoned?
Done. I just realized that is_nothrow_callable also handles crazy
member pointer cases.
Used fold expression instead of __and_ for consistency.
>
>
>> @@ -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 =
>
>
> If this isn't static now it could be called simply __vtable, the _S_
> prefix is misleading. How many of these _S_vtable variables actually
> need to be static? If they're all trivial types and constexpr then it
> probably doesn't matter either way, there shouldn't be any difference.
Ah that's an oversight. Moved the static variable out of visit().
_S_vtable needs to be static, otherwise runtime O(n) assignment will
happen, where n is the size of _S_vtable.
--
Regards,
Tim Shen
[-- Attachment #2: a2.diff --]
[-- Type: text/x-patch, Size: 10744 bytes --]
commit 896de64db984a82f59090c58ee86555b79052346
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 89ca979..32c0dc3 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -40,7 +40,6 @@
#include <bits/enable_special_members.h>
#include <bits/functexcept.h>
#include <bits/move.h>
-#include <bits/uses_allocator.h>
#include <bits/functional_hash.h>
namespace std _GLIBCXX_VISIBILITY(default)
@@ -202,14 +201,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 +344,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)
{
@@ -1033,84 +983,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;
@@ -1300,10 +1172,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 8250a95..a67b651 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>>, "");
@@ -324,9 +299,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;
@@ -339,11 +312,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();
[-- Attachment #3: b2.diff --]
[-- Type: text/x-patch, Size: 28893 bytes --]
commit 7af7721bc130f768f5659c8faf50e3d76d63a7d1
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 32c0dc3..a961a05 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -41,6 +41,7 @@
#include <bits/functexcept.h>
#include <bits/move.h>
#include <bits/functional_hash.h>
+#include <ext/aligned_buffer.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -153,33 +154,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Alternative>
using __storage = _Alternative;
- template<typename _Type, bool __is_literal = std::is_literal_type_v<_Type>>
+ // _Uninitialized<T> is guaranteed to be a literal type, even if T is not.
+ // We have to do this, because [basic.types]p10.5.3 (n4606) is not implemented
+ // yet. When it's implemented, _Uninitialized<T> can be changed to the alias
+ // to T, therefore equivalent to being removed entirely.
+ //
+ // Another reason we may not want to remove _Uninitialzied<T> may be that, we
+ // want _Uninitialized<T> to be trivially destructible, no matter whether T
+ // is; but we will see.
+ 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)...); }
- typename std::aligned_storage<sizeof(_Type), alignof(_Type)>::type
- _M_storage;
+ const _Type& _M_get() const &
+ { return *_M_storage._M_ptr(); }
+
+ _Type& _M_get() &
+ { return *_M_storage._M_ptr(); }
+
+ const _Type&& _M_get() const &&
+ { return std::move(*_M_storage._M_ptr()); }
+
+ _Type&& _M_get() &&
+ { return std::move(*_M_storage._M_ptr()); }
+
+ __gnu_cxx::__aligned_membuf<_Type> _M_storage;
};
// Given a qualified storage type, return the desired reference.
@@ -194,6 +222,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>
@@ -201,13 +244,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>
@@ -223,90 +266,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::index_sequence_for<_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()
@@ -315,7 +376,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())
{
@@ -323,31 +383,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())
{
@@ -367,11 +428,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;
}
@@ -380,7 +441,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())
{
@@ -399,32 +460,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?
@@ -489,15 +541,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;
@@ -597,9 +640,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 _Tp>
static constexpr void
- _S_apply_single_alt(auto& __element)
+ _S_apply_single_alt(_Tp& __element)
{
using _Alternative = variant_alternative_t<__index, decay_t<_First>>;
using _Qualified_storage = __reserved_type_map<
@@ -655,23 +698,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");
@@ -680,7 +723,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");
@@ -690,7 +733,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");
@@ -699,7 +742,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");
@@ -709,7 +752,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...>>;
@@ -717,12 +761,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...>>;
@@ -730,12 +775,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");
@@ -744,7 +790,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...>,
@@ -754,64 +801,36 @@ _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::index_sequence_for<_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::index_sequence_for<_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); }
@@ -1102,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 a67b651..ab8ada2 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), "");
}
}
@@ -262,14 +288,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()
[-- Attachment #4: c2.diff --]
[-- Type: text/x-patch, Size: 10760 bytes --]
commit e1673a8fc7ea3af6b86ce998379fb74626fd7f40
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 a961a05..fa1e654 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -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())
{
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index ab8ada2..087a17c 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() { }
@@ -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), "");
+}
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()
{
[-- Attachment #5: d2.diff --]
[-- Type: text/x-patch, Size: 20120 bytes --]
commit 7f64577f6f54e820f7a313085d09c5f64caa6c1e
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 fa1e654..dd6109d 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -41,11 +41,34 @@
#include <bits/functexcept.h>
#include <bits/move.h>
#include <bits/functional_hash.h>
+#include <bits/invoke.h>
#include <ext/aligned_buffer.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<T> is guaranteed to be a literal type, even if T is not.
// We have to do this, because [basic.types]p10.5.3 (n4606) is not implemented
// yet. When it's implemented, _Uninitialized<T> can be changed to the alias
@@ -210,16 +214,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__gnu_cxx::__aligned_membuf<_Type> _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>
@@ -242,7 +240,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
@@ -256,14 +254,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>
@@ -285,7 +283,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>
@@ -389,8 +390,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;
}
@@ -402,7 +402,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;
}
@@ -422,8 +422,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());
}
}
@@ -469,8 +468,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());
}
}
@@ -555,20 +553,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
@@ -592,108 +576,115 @@ _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 _Tp>
static constexpr void
_S_apply_single_alt(_Tp& __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();
}
+
+ static constexpr auto _S_vtable = _S_apply();
};
template<size_t _Np, typename _Tp>
@@ -722,22 +713,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)
{
@@ -860,7 +835,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 { };
@@ -965,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...>;
@@ -1127,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());
}
@@ -1268,17 +1239,21 @@ _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 =
- __detail::__variant::__gen_vtable<
- _Result_type, _Visitor&&, _Variants&&...>::_S_apply();
- auto __func_ptr = _S_vtable._M_access(__variants.index()...);
+
+ constexpr auto& __vtable = __detail::__variant::__gen_vtable<
+ _Result_type, _Visitor&&, _Variants&&...>::_S_vtable;
+
+ auto __func_ptr = __vtable._M_access(__variants.index()...);
return (*__func_ptr)(std::forward<_Visitor>(__visitor),
- __detail::__variant::__get_storage(__variants)...);
+ std::forward<_Variants>(__variants)...);
}
template<typename... _Types>
@@ -1297,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 087a17c..a8ffaea 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -275,6 +275,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()
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-12-03 3:15 ` Tim Shen
@ 2016-12-06 10:30 ` Jonathan Wakely
2016-12-06 11:52 ` Tim Shen
0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Wakely @ 2016-12-06 10:30 UTC (permalink / raw)
To: Tim Shen; +Cc: libstdc++, gcc-patches
On 02/12/16 19:14 -0800, Tim Shen wrote:
>On Wed, Nov 30, 2016 at 8:27 AM, Jonathan Wakely wrote:
>> On 26/11/16 21:38 -0800, Tim Shen wrote:
>>>
>>> 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.
>>
>>
>> Yay! less code.
>
>Yay! Also removed the unused #include.
>
>>
>>> - template<typename _Type, bool __is_literal =
>>> std::is_literal_type_v<_Type>>
>>> + // _Uninitialized nullify the destructor calls.
>>
>>
>> This wording confused me slightly. How about:
>>
>> "_Uninitialized makes destructors trivial"
>
>Change this section of comment to the discussed content.
>
>>
>>> + // 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.
>>
>>
>> Please change "it's slow" to "that's slow".
>
>N/A.
>
>>
>>> + template<typename _Type, bool = std::is_literal_type_v<_Type>>
>>> struct _Uninitialized;
>>
>>
>> I'm still unsure that is_literal_type is the right trait here. If it's
>> definitely right then we should probably *not* deprecate it in C++17!
>
>Already discussed.
>
>>
>>> 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;
>>
>>
>> I think this could use __aligned_membuf, which would reduce the
>> alignment requirements for some types (e.g. long long on x86-32).
>
>Done.
>
>>
>> That would also mean you get the _M_ptr() member so don't need all the
>> casts.
>>
>>> + ~_Variant_storage()
>>> + { _M_destroy_impl(std::make_index_sequence<sizeof...(_Types)>{}); }
>>
>>
>> You can use index_sequence_for<_Types...> here.
>
>Done
>
>>
>>> @@ -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>
>>
>>
>> This needs to be _Tp not T
>
>Done.
>
>>
>>> + return __lhs._M_equal_to(__rhs,
>>> +
>>> std::make_index_sequence<sizeof...(_Types)>{});
>>
>>
>> Another one that could use index_sequence_for<_Types...>
>
>Done.
>
>>
>>> + return __lhs._M_less_than(__rhs,
>>> +
>>> std::make_index_sequence<sizeof...(_Types)>{});
>>
>>
>> Same again.
>
>Same again. ;)
>
>>
>>
>>> * 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
>>> @@ -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) { }
>>> };
>>>
>>> + 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(); }
>>
>>
>> These can also use index_sequence_for<_Types...>
>
>Done.
>
>>
>>> @@ -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)>>
>>
>>
>> And again.
>
>And again.
>
>>
>>> {
>>> 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>()))
>>> + && ...))
>>
>>
>> This could be
>> __and_<is_nothrow_callable<hash<decay_t<_Types>>(_Types)>...>
>> but I'm not sure it would be an improvement. The is_callable check is
>> expensive, but maybe we need it anyway to correctly disable this
>> function if the hash specialization should be posisoned?
>
>Done. I just realized that is_nothrow_callable also handles crazy
>member pointer cases.
>
>Used fold expression instead of __and_ for consistency.
>
>>
>>
>>> @@ -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 =
>>
>>
>> If this isn't static now it could be called simply __vtable, the _S_
>> prefix is misleading. How many of these _S_vtable variables actually
>> need to be static? If they're all trivial types and constexpr then it
>> probably doesn't matter either way, there shouldn't be any difference.
>
>Ah that's an oversight. Moved the static variable out of visit().
>_S_vtable needs to be static, otherwise runtime O(n) assignment will
>happen, where n is the size of _S_vtable.
This looks good - OK for trunk, thanks!
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-12-06 10:30 ` Jonathan Wakely
@ 2016-12-06 11:52 ` Tim Shen
2016-12-06 12:49 ` Jonathan Wakely
0 siblings, 1 reply; 10+ messages in thread
From: Tim Shen @ 2016-12-06 11:52 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches
On Tue, Dec 6, 2016 at 2:30 AM, Jonathan Wakely wrote:
> This looks good - OK for trunk, thanks!
Committed.
Thanks!
--
Regards,
Tim Shen
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-12-06 11:52 ` Tim Shen
@ 2016-12-06 12:49 ` Jonathan Wakely
2016-12-06 14:37 ` Jonathan Wakely
0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Wakely @ 2016-12-06 12:49 UTC (permalink / raw)
To: Tim Shen; +Cc: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 204 bytes --]
On 06/12/16 03:52 -0800, Tim Shen wrote:
>On Tue, Dec 6, 2016 at 2:30 AM, Jonathan Wakely wrote:
>> This looks good - OK for trunk, thanks!
>
>Committed.
>
>Thanks!
ChangeLog dates fixed by this patch.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1617 bytes --]
commit c3651cf0403b826414b8376bb29b4757530f4eec
Author: redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue Dec 6 12:48:54 2016 +0000
Fix libstdc++-v3/ChangeLog dates
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@243299 138bc75d-0d04-0410-961f-82ee72b054a4
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 47e9abf..b8edb7b 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -9,14 +9,14 @@
Guard with #ifndef __cpp_lib_addressof_constexpr.
(operator->()): Use std::__addressof if it's constexpr.
-2016-11-27 Tim Shen <timshen@google.com>
+2016-12-06 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.
-2016-12-07 Tim Shen <timshen@google.com>
+2016-12-06 Tim Shen <timshen@google.com>
* include/bits/enable_special_members.h: Make
_Enable_default_constructor constexpr.
@@ -24,13 +24,13 @@
std::hash): Sfinae on emplace and std::swap; handle __poison_hash bases
of duplicated types.
-2016-12-07 Tim Shen <timshen@google.com>
+2016-12-06 Tim Shen <timshen@google.com>
* include/std/variant (std::get, operator==): Implement constexpr
comparison and get<>.
* testsuite/20_util/variant/compile.cc: Tests.
-2016-12-07 Tim Shen <timshen@google.com>
+2016-12-06 Tim Shen <timshen@google.com>
* include/std/variant (__erased_use_alloc_ctor,
_Variant_base::_Variant_base, variant::variant): Remove uses-allocator
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-12-06 12:49 ` Jonathan Wakely
@ 2016-12-06 14:37 ` Jonathan Wakely
2016-12-06 20:10 ` Tim Shen
0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Wakely @ 2016-12-06 14:37 UTC (permalink / raw)
To: Tim Shen; +Cc: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 449 bytes --]
On 06/12/16 12:49 +0000, Jonathan Wakely wrote:
>On 06/12/16 03:52 -0800, Tim Shen wrote:
>>On Tue, Dec 6, 2016 at 2:30 AM, Jonathan Wakely wrote:
>>>This looks good - OK for trunk, thanks!
>>
>>Committed.
>>
>>Thanks!
>
>ChangeLog dates fixed by this patch.
And pretty printer fixed by this one.
The "vref" test originally testsed variant<string_view&> but is no
longer needed, as that isn't supported.
Tested x86_64-linux, committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1914 bytes --]
commit 2f135ef76712b96e3dd799dfbb17e8d16545b115
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue Dec 6 14:24:13 2016 +0000
Fix pretty-printer for std::variant
* python/libstdcxx/v6/printers.py (StdVariantPrinter): Update for new
data member name.
* testsuite/libstdc++-prettyprinters/cxx17.cc: Remove redundant test.
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index bad42b4..ff428e8 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -1002,7 +1002,7 @@ class StdVariantPrinter(SingleObjContainerPrinter):
visualizer = None
else:
self.contained_type = alternatives[int(self.index)]
- addr = val['_M_union']['_M_first']['_M_storage'].address
+ addr = val['_M_u']['_M_first']['_M_storage'].address
contained_value = addr.cast(self.contained_type.pointer()).dereference()
visualizer = gdb.default_visualizer(contained_value)
super (StdVariantPrinter, self).__init__(contained_value, visualizer, 'array')
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc
index 96be8c7..69c16c1 100644
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc
@@ -86,8 +86,6 @@ main()
// { dg-final { note-test v3 {std::variant<float, int, std::string_view> [index 1] = {3}} } }
variant<float, int, string_view> v4{ str };
// { dg-final { note-test v4 {std::variant<float, int, std::string_view> [index 2] = {"string"}} } }
- variant<string_view> vref{str};
-// { dg-final { note-test vref {std::variant<std::string_view> [index 0] = {"string"}} } }
map<int, string_view> m{ {1, "one"} };
map<int, string_view>::node_type n0;
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Patches] Add variant constexpr support for visit, comparisons and get
2016-12-06 14:37 ` Jonathan Wakely
@ 2016-12-06 20:10 ` Tim Shen
0 siblings, 0 replies; 10+ messages in thread
From: Tim Shen @ 2016-12-06 20:10 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc-patches
On Tue, Dec 6, 2016 at 6:37 AM, Jonathan Wakely <jwakely@redhat.com> wrote:
> On 06/12/16 12:49 +0000, Jonathan Wakely wrote:
>>
>> On 06/12/16 03:52 -0800, Tim Shen wrote:
>>>
>>> On Tue, Dec 6, 2016 at 2:30 AM, Jonathan Wakely wrote:
>>>>
>>>> This looks good - OK for trunk, thanks!
>>>
>>>
>>> Committed.
>>>
>>> Thanks!
>>
>>
>> ChangeLog dates fixed by this patch.
>
>
> And pretty printer fixed by this one.
>
> The "vref" test originally testsed variant<string_view&> but is no
> longer needed, as that isn't supported.
>
> Tested x86_64-linux, committed to trunk.
>
Thanks!
Just figured out that I need to run prettyprinters.exp (I usually just
run "conformance.exp=20_util/variant/*") to catch the failures...
--
Regards,
Tim Shen
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2016-12-06 20:10 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-27 5:38 [Patches] Add variant constexpr support for visit, comparisons and get Tim Shen
2016-11-30 16:27 ` Jonathan Wakely
2016-12-01 3:29 ` Tim Shen
2016-12-01 11:16 ` Jonathan Wakely
2016-12-03 3:15 ` Tim Shen
2016-12-06 10:30 ` Jonathan Wakely
2016-12-06 11:52 ` Tim Shen
2016-12-06 12:49 ` Jonathan Wakely
2016-12-06 14:37 ` Jonathan Wakely
2016-12-06 20:10 ` Tim Shen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).