Skip to content

Commit 3412bc7

Browse files
H-G-HristovZingam
andauthored
[libc++][variant] P2637R3: Member visit (std::variant) (#76447)
Implements parts of: `P2637R3` https://wg21.link/P2637R3 (https://eel.is/c++draft/variant.visit) Implements: `variant.visit()` `variant.visit<R>()` The tests are as close as possible to the non-member function. To land after: #76268 --------- Co-authored-by: Zingam <[email protected]>
1 parent 6bb5c98 commit 3412bc7

File tree

7 files changed

+706
-7
lines changed

7 files changed

+706
-7
lines changed

libcxx/docs/Status/Cxx2cPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"`P0792R14 <https://wg21.link/P0792R14>`__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","",""
1818
"`P2874R2 <https://wg21.link/P2874R2>`__","LWG","Mandating Annex D Require No More","Varna June 2023","","",""
1919
"`P2757R3 <https://wg21.link/P2757R3>`__","LWG","Type-checking format args","Varna June 2023","","","|format|"
20-
"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","","","|format|"
20+
"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","|Partial|","18.0",""
2121
"`P2641R4 <https://wg21.link/P2641R4>`__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","",""
2222
"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","|Complete|","18.0",""
2323
"`P2697R1 <https://wg21.link/P2697R1>`__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0",""

libcxx/include/__config

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,11 @@ __sanitizer_verify_double_ended_contiguous_container(const void*, const void*, c
15131513
# define _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
15141514
# endif
15151515

1516+
// Clang-18 has support for deducing this, but it does not set the FTM.
1517+
# if defined(__cpp_explicit_this_parameter) || (defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 1800)
1518+
# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER
1519+
# endif
1520+
15161521
#endif // __cplusplus
15171522

15181523
#endif // _LIBCPP___CONFIG

libcxx/include/variant

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ namespace std {
6969
7070
// 20.7.2.6, swap
7171
void swap(variant&) noexcept(see below);
72+
73+
// [variant.visit], visitation
74+
template<class Self, class Visitor>
75+
constexpr decltype(auto) visit(this Self&&, Visitor&&); // Since C++26
76+
template<class R, class Self, class Visitor>
77+
constexpr R visit(this Self&&, Visitor&&); // Since C++26
7278
};
7379
7480
// 20.7.3, variant helper classes
@@ -235,6 +241,7 @@ namespace std {
235241
#include <__type_traits/void_t.h>
236242
#include <__utility/declval.h>
237243
#include <__utility/forward.h>
244+
#include <__utility/forward_like.h>
238245
#include <__utility/in_place.h>
239246
#include <__utility/move.h>
240247
#include <__utility/swap.h>
@@ -1130,6 +1137,19 @@ using __best_match_t = typename invoke_result_t<_MakeOverloads<_Types...>, _Tp,
11301137

11311138
} // namespace __variant_detail
11321139

1140+
template <class _Visitor, class... _Vs, typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...>>
1141+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto)
1142+
visit(_Visitor&& __visitor, _Vs&&... __vs);
1143+
1144+
# if _LIBCPP_STD_VER >= 20
1145+
template <class _Rp,
1146+
class _Visitor,
1147+
class... _Vs,
1148+
typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...>>
1149+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
1150+
visit(_Visitor&& __visitor, _Vs&&... __vs);
1151+
# endif
1152+
11331153
template <class... _Types>
11341154
class _LIBCPP_TEMPLATE_VIS _LIBCPP_DECLSPEC_EMPTY_BASES variant
11351155
: private __sfinae_ctor_base< __all<is_copy_constructible_v<_Types>...>::value,
@@ -1273,6 +1293,27 @@ public:
12731293
__impl_.__swap(__that.__impl_);
12741294
}
12751295

1296+
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
1297+
// Helper class to implement [variant.visit]/10
1298+
// Constraints: The call to visit does not use an explicit template-argument-list
1299+
// that begins with a type template-argument.
1300+
struct __variant_visit_barrier_tag {
1301+
_LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default;
1302+
};
1303+
1304+
template <__variant_visit_barrier_tag = __variant_visit_barrier_tag{}, class _Self, class _Visitor>
1305+
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
1306+
using _VariantT = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
1307+
return std::visit(std::forward<_Visitor>(__visitor), (_VariantT)__self);
1308+
}
1309+
1310+
template <class _Rp, class _Self, class _Visitor>
1311+
_LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) {
1312+
using _VariantT = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
1313+
return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_VariantT)__self);
1314+
}
1315+
# endif
1316+
12761317
private:
12771318
__variant_detail::__impl<_Types...> __impl_;
12781319

@@ -1511,7 +1552,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr vo
15111552
}
15121553
}
15131554

1514-
template < class _Visitor, class... _Vs, typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
1555+
template < class _Visitor, class... _Vs, typename>
15151556
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto)
15161557
visit(_Visitor&& __visitor, _Vs&&... __vs) {
15171558
using __variant_detail::__visitation::__variant;
@@ -1520,10 +1561,7 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) {
15201561
}
15211562

15221563
# if _LIBCPP_STD_VER >= 20
1523-
template < class _Rp,
1524-
class _Visitor,
1525-
class... _Vs,
1526-
typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
1564+
template < class _Rp, class _Visitor, class... _Vs, typename>
15271565
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
15281566
visit(_Visitor&& __visitor, _Vs&&... __vs) {
15291567
using __variant_detail::__visitation::__variant;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
10+
// The tested functionality needs deducing this.
11+
// UNSUPPORTED: clang-16 || clang-17
12+
// XFAIL: apple-clang
13+
14+
// <variant>
15+
16+
// class variant;
17+
// template<class Self, class Visitor>
18+
// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
19+
// template<class R, class Self, class Visitor>
20+
// constexpr R visit(this Self&&, Visitor&&); // since C++26
21+
22+
#include <variant>
23+
24+
#include "test_macros.h"
25+
26+
struct Incomplete;
27+
template <class T>
28+
struct Holder {
29+
T t;
30+
};
31+
32+
constexpr bool test(bool do_it) {
33+
if (do_it) {
34+
std::variant<Holder<Incomplete>*, int> v = nullptr;
35+
36+
v.visit([](auto) {});
37+
v.visit([](auto) -> Holder<Incomplete>* { return nullptr; });
38+
v.visit<void>([](auto) {});
39+
v.visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; });
40+
}
41+
return true;
42+
}
43+
44+
int main(int, char**) {
45+
test(true);
46+
static_assert(test(true));
47+
48+
return 0;
49+
}

0 commit comments

Comments
 (0)