Commit 484308ad authored by jwakely2's avatar jwakely2
Browse files

libstdc++: Allow visiting inherited variants [PR 90943]

Implement the changes from P2162R2 (as a DR for C++17).

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.
parent fb790888
// <variant> -*- C++ -*-
// Copyright (C) 2021 Jonathan Wakely
// Copyright (C) 2016-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
......@@ -71,7 +73,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 +204,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>>
......@@ -1739,20 +1763,23 @@ namespace __variant
constexpr decltype(auto)
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 = std::invoke_result_t<_Visitor,
decltype(std::get<0>(std::declval<_Variants>()))...>;
decltype(std::get<0>(__variant::__as(std::declval<_Variants>())))...>;
using _Tag = __detail::__variant::__deduce_visit_result<_Result_type>;
if constexpr (sizeof...(_Variants) == 1)
{
using _Vp = decltype(__variant::__as(std::declval<_Variants>()...));
constexpr bool __visit_rettypes_match =
__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,
......@@ -1763,12 +1790,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
......@@ -1776,11 +1803,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
......
......@@ -163,7 +163,7 @@
#define __cpp_lib_string_view 201803L
// #define __cpp_lib_to_chars 201611L
#define __cpp_lib_unordered_map_try_emplace 201411
#define __cpp_lib_variant 201606L
#define __cpp_lib_variant 202102L
#endif
#if __cplusplus > 201703L
......
// { 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 );
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment