Skip to content

Commit 51faba3

Browse files
rarutyunldionne
authored andcommitted
[libc++] Implement P0655R1 visit<R>: Explicit Return Type for visit
Differential Revision: https://reviews.llvm.org/D92044
1 parent 95f0d1e commit 51faba3

File tree

6 files changed

+583
-81
lines changed

6 files changed

+583
-81
lines changed

libcxx/docs/Cxx2aStatusPaperStatus.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"`P0595R2 <https://wg21.link/P0595R2>`__","CWG","P0595R2 std::is_constant_evaluated()","San Diego","|Complete|","9.0"
6060
"`P0602R4 <https://wg21.link/P0602R4>`__","LWG","variant and optional should propagate copy/move triviality","San Diego","|Complete|","8.0"
6161
"`P0608R3 <https://wg21.link/P0608R3>`__","LWG","A sane variant converting constructor","San Diego","|Complete|","9.0"
62-
"`P0655R1 <https://wg21.link/P0655R1>`__","LWG","visit<R>: Explicit Return Type for visit","San Diego","* *",""
62+
"`P0655R1 <https://wg21.link/P0655R1>`__","LWG","visit<R>: Explicit Return Type for visit","San Diego","|Complete|","12.0"
6363
"`P0771R1 <https://wg21.link/P0771R1>`__","LWG","std::function move constructor should be noexcept","San Diego","|Complete|","6.0"
6464
"`P0896R4 <https://wg21.link/P0896R4>`__","LWG","The One Ranges Proposal","San Diego","* *",""
6565
"`P0899R1 <https://wg21.link/P0899R1>`__","LWG","P0899R1 - LWG 3016 is not a defect","San Diego","|Nothing To Do|",""

libcxx/include/variant

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ namespace std {
169169
template <class Visitor, class... Variants>
170170
constexpr see below visit(Visitor&&, Variants&&...);
171171
172+
template <class R, class Visitor, class... Variants>
173+
constexpr R visit(Visitor&&, Variants&&...); // since C++20
174+
172175
// 20.7.7, class monostate
173176
struct monostate;
174177
@@ -583,6 +586,16 @@ struct __variant {
583586
__make_value_visitor(_VSTD::forward<_Visitor>(__visitor)),
584587
_VSTD::forward<_Vs>(__vs)...);
585588
}
589+
#if _LIBCPP_STD_VER > 17
590+
template <class _Rp, class _Visitor, class... _Vs>
591+
inline _LIBCPP_INLINE_VISIBILITY
592+
static constexpr _Rp __visit_value(_Visitor&& __visitor,
593+
_Vs&&... __vs) {
594+
return __visit_alt(
595+
__make_value_visitor<_Rp>(_VSTD::forward<_Visitor>(__visitor)),
596+
_VSTD::forward<_Vs>(__vs)...);
597+
}
598+
#endif
586599

587600
private:
588601
template <class _Visitor, class... _Values>
@@ -605,12 +618,43 @@ private:
605618
_Visitor&& __visitor;
606619
};
607620

621+
#if _LIBCPP_STD_VER > 17
622+
template <class _Rp, class _Visitor>
623+
struct __value_visitor_return_type {
624+
template <class... _Alts>
625+
inline _LIBCPP_INLINE_VISIBILITY
626+
constexpr _Rp operator()(_Alts&&... __alts) const {
627+
__std_visit_exhaustive_visitor_check<
628+
_Visitor,
629+
decltype((_VSTD::forward<_Alts>(__alts).__value))...>();
630+
if constexpr (is_void_v<_Rp>) {
631+
_VSTD::__invoke_constexpr(_VSTD::forward<_Visitor>(__visitor),
632+
_VSTD::forward<_Alts>(__alts).__value...);
633+
}
634+
else {
635+
return _VSTD::__invoke_constexpr(_VSTD::forward<_Visitor>(__visitor),
636+
_VSTD::forward<_Alts>(__alts).__value...);
637+
}
638+
}
639+
640+
_Visitor&& __visitor;
641+
};
642+
#endif
643+
608644
template <class _Visitor>
609645
inline _LIBCPP_INLINE_VISIBILITY
610646
static constexpr auto __make_value_visitor(_Visitor&& __visitor) {
611647
return __value_visitor<_Visitor>{_VSTD::forward<_Visitor>(__visitor)};
612648
}
649+
650+
#if _LIBCPP_STD_VER > 17
651+
template <class _Rp, class _Visitor>
652+
inline _LIBCPP_INLINE_VISIBILITY
653+
static constexpr auto __make_value_visitor(_Visitor&& __visitor) {
654+
return __value_visitor_return_type<_Rp, _Visitor>{_VSTD::forward<_Visitor>(__visitor)};
655+
}
613656
};
657+
#endif
614658

615659
} // namespace __visitation
616660

@@ -1594,18 +1638,37 @@ constexpr bool operator>=(const variant<_Types...>& __lhs,
15941638
template <class _Visitor, class... _Vs>
15951639
inline _LIBCPP_INLINE_VISIBILITY
15961640
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
1597-
constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
1598-
using __variant_detail::__visitation::__variant;
1599-
bool __results[] = {__vs.valueless_by_exception()...};
1600-
for (bool __result : __results) {
1601-
if (__result) {
1641+
constexpr void __throw_if_valueless(_Visitor&& __visitor, _Vs&&... __vs) {
1642+
const bool __valueless = (... || __vs.valueless_by_exception());
1643+
if (__valueless) {
16021644
__throw_bad_variant_access();
1603-
}
16041645
}
1646+
}
1647+
1648+
template <class _Visitor, class... _Vs>
1649+
inline _LIBCPP_INLINE_VISIBILITY
1650+
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
1651+
constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
1652+
using __variant_detail::__visitation::__variant;
1653+
_VSTD::__throw_if_valueless(_VSTD::forward<_Visitor>(__visitor),
1654+
_VSTD::forward<_Vs>(__vs)...);
16051655
return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor),
16061656
_VSTD::forward<_Vs>(__vs)...);
16071657
}
16081658

1659+
#if _LIBCPP_STD_VER > 17
1660+
template <class _Rp, class _Visitor, class... _Vs>
1661+
inline _LIBCPP_INLINE_VISIBILITY
1662+
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
1663+
constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) {
1664+
using __variant_detail::__visitation::__variant;
1665+
_VSTD::__throw_if_valueless(_VSTD::forward<_Visitor>(__visitor),
1666+
_VSTD::forward<_Vs>(__vs)...);
1667+
return __variant::__visit_value<_Rp>(_VSTD::forward<_Visitor>(__visitor),
1668+
_VSTD::forward<_Vs>(__vs)...);
1669+
}
1670+
#endif
1671+
16091672
struct _LIBCPP_TEMPLATE_VIS monostate {};
16101673

16111674
inline _LIBCPP_INLINE_VISIBILITY

libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ constexpr bool test(bool do_it)
3232
std::variant<Holder<Incomplete>*, int> v = nullptr;
3333
std::visit([](auto){}, v);
3434
std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
35+
#if TEST_STD_VER > 17
36+
std::visit<void>([](auto){}, v);
37+
std::visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
38+
#endif
3539
}
3640
return true;
3741
}

libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -27,70 +27,8 @@
2727
#include <variant>
2828

2929
#include "test_macros.h"
30-
#include "type_id.h"
3130
#include "variant_test_helpers.h"
3231

33-
enum CallType : unsigned {
34-
CT_None,
35-
CT_NonConst = 1,
36-
CT_Const = 2,
37-
CT_LValue = 4,
38-
CT_RValue = 8
39-
};
40-
41-
inline constexpr CallType operator|(CallType LHS, CallType RHS) {
42-
return static_cast<CallType>(static_cast<unsigned>(LHS) |
43-
static_cast<unsigned>(RHS));
44-
}
45-
46-
struct ForwardingCallObject {
47-
48-
template <class... Args>
49-
ForwardingCallObject& operator()(Args&&...) & {
50-
set_call<Args &&...>(CT_NonConst | CT_LValue);
51-
return *this;
52-
}
53-
54-
template <class... Args>
55-
const ForwardingCallObject& operator()(Args&&...) const & {
56-
set_call<Args &&...>(CT_Const | CT_LValue);
57-
return *this;
58-
}
59-
60-
template <class... Args>
61-
ForwardingCallObject&& operator()(Args&&...) && {
62-
set_call<Args &&...>(CT_NonConst | CT_RValue);
63-
return std::move(*this);
64-
}
65-
66-
template <class... Args>
67-
const ForwardingCallObject&& operator()(Args&&...) const && {
68-
set_call<Args &&...>(CT_Const | CT_RValue);
69-
return std::move(*this);
70-
}
71-
72-
template <class... Args> static void set_call(CallType type) {
73-
assert(last_call_type == CT_None);
74-
assert(last_call_args == nullptr);
75-
last_call_type = type;
76-
last_call_args = std::addressof(makeArgumentID<Args...>());
77-
}
78-
79-
template <class... Args> static bool check_call(CallType type) {
80-
bool result = last_call_type == type && last_call_args &&
81-
*last_call_args == makeArgumentID<Args...>();
82-
last_call_type = CT_None;
83-
last_call_args = nullptr;
84-
return result;
85-
}
86-
87-
static CallType last_call_type;
88-
static const TypeID *last_call_args;
89-
};
90-
91-
CallType ForwardingCallObject::last_call_type = CT_None;
92-
const TypeID *ForwardingCallObject::last_call_args = nullptr;
93-
9432
void test_call_operator_forwarding() {
9533
using Fn = ForwardingCallObject;
9634
Fn obj{};
@@ -296,18 +234,6 @@ void test_return_type() {
296234
}
297235
}
298236

299-
struct ReturnFirst {
300-
template <class... Args> constexpr int operator()(int f, Args &&...) const {
301-
return f;
302-
}
303-
};
304-
305-
struct ReturnArity {
306-
template <class... Args> constexpr int operator()(Args &&...) const {
307-
return sizeof...(Args);
308-
}
309-
};
310-
311237
void test_constexpr() {
312238
constexpr ReturnFirst obj{};
313239
constexpr ReturnArity aobj{};

0 commit comments

Comments
 (0)