libstdc++: Allow visiting inherited variants [PR 90943]
Implement the changes from P2162R2 (as a DR for C++17). Signed-off-by: Jonathan Wakely <jwakely@redhat.com> libstdc++-v3/ChangeLog: PR libstdc++/90943 * include/std/variant (__cpp_lib_variant): Update value. (__detail::__variant::__as): New helpers implementing the as-variant exposition-only function templates. (visit, visit<R>): Use __as to upcast the variant parameters. * include/std/version (__cpp_lib_variant): Update value. * testsuite/20_util/variant/visit_inherited.cc: New test.
This commit is contained in:
@@ -71,7 +71,7 @@ namespace __variant
|
||||
} // namespace __variant
|
||||
} // namespace __detail
|
||||
|
||||
#define __cpp_lib_variant 201606L
|
||||
#define __cpp_lib_variant 202102L
|
||||
|
||||
template<typename... _Types> class tuple;
|
||||
template<typename... _Types> class variant;
|
||||
@@ -202,6 +202,28 @@ namespace __variant
|
||||
std::forward<_Variants>(__variants)...);
|
||||
}
|
||||
|
||||
// The __as function templates implement the exposition-only "as-variant"
|
||||
|
||||
template<typename... _Types>
|
||||
constexpr std::variant<_Types...>&
|
||||
__as(std::variant<_Types...>& __v)
|
||||
{ return __v; }
|
||||
|
||||
template<typename... _Types>
|
||||
constexpr const std::variant<_Types...>&
|
||||
__as(const std::variant<_Types...>& __v) noexcept
|
||||
{ return __v; }
|
||||
|
||||
template<typename... _Types>
|
||||
constexpr std::variant<_Types...>&&
|
||||
__as(std::variant<_Types...>&& __v) noexcept
|
||||
{ return std::move(__v); }
|
||||
|
||||
template<typename... _Types>
|
||||
constexpr const std::variant<_Types...>&&
|
||||
__as(const std::variant<_Types...>&& __v) noexcept
|
||||
{ return std::move(__v); }
|
||||
|
||||
// _Uninitialized<T> is guaranteed to be a trivially destructible type,
|
||||
// even if T is not.
|
||||
template<typename _Type, bool = std::is_trivially_destructible_v<_Type>>
|
||||
@@ -1063,8 +1085,12 @@ namespace __variant
|
||||
std::index_sequence<__indices...>>
|
||||
: _Base_dedup<__indices, __poison_hash<remove_const_t<_Types>>>... { };
|
||||
|
||||
template<size_t _Np, typename _Variant>
|
||||
using __get_t = decltype(std::get<_Np>(std::declval<_Variant>()));
|
||||
// Equivalent to decltype(get<_Np>(as-variant(declval<_Variant>())))
|
||||
template<size_t _Np, typename _Variant,
|
||||
typename _AsV = decltype(__variant::__as(std::declval<_Variant>())),
|
||||
typename _Tp = variant_alternative_t<_Np, remove_reference_t<_AsV>>>
|
||||
using __get_t
|
||||
= conditional_t<is_lvalue_reference_v<_Variant>, _Tp&, _Tp&&>;
|
||||
|
||||
// Return type of std::visit.
|
||||
template<typename _Visitor, typename... _Variants>
|
||||
@@ -1741,7 +1767,9 @@ namespace __variant
|
||||
constexpr __detail::__variant::__visit_result_t<_Visitor, _Variants...>
|
||||
visit(_Visitor&& __visitor, _Variants&&... __variants)
|
||||
{
|
||||
if ((__variants.valueless_by_exception() || ...))
|
||||
namespace __variant = std::__detail::__variant;
|
||||
|
||||
if ((__variant::__as(__variants).valueless_by_exception() || ...))
|
||||
__throw_bad_variant_access("std::visit: variant is valueless");
|
||||
|
||||
using _Result_type
|
||||
@@ -1751,10 +1779,11 @@ namespace __variant
|
||||
|
||||
if constexpr (sizeof...(_Variants) == 1)
|
||||
{
|
||||
using _Vp = decltype(__variant::__as(std::declval<_Variants>()...));
|
||||
|
||||
constexpr bool __visit_rettypes_match = __detail::__variant::
|
||||
__check_visitor_results<_Visitor, _Variants...>(
|
||||
std::make_index_sequence<
|
||||
std::variant_size<remove_reference_t<_Variants>...>::value>());
|
||||
__check_visitor_results<_Visitor, _Vp>(
|
||||
make_index_sequence<variant_size_v<remove_reference_t<_Vp>>>());
|
||||
if constexpr (!__visit_rettypes_match)
|
||||
{
|
||||
static_assert(__visit_rettypes_match,
|
||||
@@ -1765,12 +1794,12 @@ namespace __variant
|
||||
else
|
||||
return std::__do_visit<_Tag>(
|
||||
std::forward<_Visitor>(__visitor),
|
||||
std::forward<_Variants>(__variants)...);
|
||||
static_cast<_Vp>(__variants)...);
|
||||
}
|
||||
else
|
||||
return std::__do_visit<_Tag>(
|
||||
std::forward<_Visitor>(__visitor),
|
||||
std::forward<_Variants>(__variants)...);
|
||||
__variant::__as(std::forward<_Variants>(__variants))...);
|
||||
}
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
@@ -1778,11 +1807,13 @@ namespace __variant
|
||||
constexpr _Res
|
||||
visit(_Visitor&& __visitor, _Variants&&... __variants)
|
||||
{
|
||||
if ((__variants.valueless_by_exception() || ...))
|
||||
namespace __variant = std::__detail::__variant;
|
||||
|
||||
if ((__variant::__as(__variants).valueless_by_exception() || ...))
|
||||
__throw_bad_variant_access("std::visit<R>: variant is valueless");
|
||||
|
||||
return std::__do_visit<_Res>(std::forward<_Visitor>(__visitor),
|
||||
std::forward<_Variants>(__variants)...);
|
||||
__variant::__as(std::forward<_Variants>(__variants))...);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
# define __cpp_lib_to_chars 201611L
|
||||
#endif
|
||||
#define __cpp_lib_unordered_map_try_emplace 201411
|
||||
#define __cpp_lib_variant 201606L
|
||||
#define __cpp_lib_variant 202102L
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
#include <variant>
|
||||
|
||||
// P2062R2 Inheriting from std::variant (resolving LWG 3052)
|
||||
|
||||
#if __cpp_lib_variant < 202102L
|
||||
#error __cpp_lib_variant has the wrong value in <variant>
|
||||
#endif
|
||||
|
||||
struct V : std::variant<int> {
|
||||
using std::variant<int>::variant;
|
||||
};
|
||||
|
||||
constexpr int
|
||||
test01()
|
||||
{
|
||||
V v = 42;
|
||||
return std::visit([](int&){ return 17; }, v);
|
||||
}
|
||||
static_assert( test01() == 17 );
|
||||
|
||||
constexpr int
|
||||
test02()
|
||||
{
|
||||
const V c = 77;
|
||||
std::variant<char*, long> x = 88L;
|
||||
return std::visit([](auto&& a, auto&& b) {
|
||||
if constexpr (std::is_same_v<decltype(a), const int&&>)
|
||||
if constexpr (std::is_same_v<decltype(b), long&&>)
|
||||
return 99;
|
||||
return 0;
|
||||
},
|
||||
std::move(c), std::move(x));
|
||||
}
|
||||
static_assert( test02() == 99 );
|
||||
Reference in New Issue
Block a user