1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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
18 // template<class Self, class Visitor>
19 // constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
24 #include <type_traits>
28 #include "test_macros.h"
29 #include "variant_test_helpers.h"
31 void test_call_operator_forwarding() {
32 using Fn
= ForwardingCallObject
;
36 { // test call operator forwarding - single variant, single arg
37 using V
= std::variant
<int>;
41 assert(Fn::check_call
<int&>(CT_NonConst
| CT_LValue
));
43 assert(Fn::check_call
<int&>(CT_Const
| CT_LValue
));
44 v
.visit(std::move(obj
));
45 assert(Fn::check_call
<int&>(CT_NonConst
| CT_RValue
));
46 v
.visit(std::move(cobj
));
47 assert(Fn::check_call
<int&>(CT_Const
| CT_RValue
));
49 { // test call operator forwarding - single variant, multi arg
50 using V
= std::variant
<int, long, double>;
54 assert(Fn::check_call
<long&>(CT_NonConst
| CT_LValue
));
56 assert(Fn::check_call
<long&>(CT_Const
| CT_LValue
));
57 v
.visit(std::move(obj
));
58 assert(Fn::check_call
<long&>(CT_NonConst
| CT_RValue
));
59 v
.visit(std::move(cobj
));
60 assert(Fn::check_call
<long&>(CT_Const
| CT_RValue
));
64 // Applies to non-member `std::visit` only.
65 void test_argument_forwarding() {
66 using Fn
= ForwardingCallObject
;
68 const auto val
= CT_LValue
| CT_NonConst
;
70 { // single argument - value type
71 using V
= std::variant
<int>;
76 assert(Fn::check_call
<int&>(val
));
78 assert(Fn::check_call
<const int&>(val
));
79 std::move(v
).visit(obj
);
80 assert(Fn::check_call
<int&&>(val
));
81 std::move(cv
).visit(obj
);
82 assert(Fn::check_call
<const int&&>(val
));
84 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
85 { // single argument - lvalue reference
86 using V
= std::variant
<int&>;
92 assert(Fn::check_call
<int&>(val
));
94 assert(Fn::check_call
<int&>(val
));
95 std::move(v
).visit(obj
);
96 assert(Fn::check_call
<int&>(val
));
97 std::move(cv
).visit(obj
);
98 assert(Fn::check_call
<int&>(val
));
101 { // single argument - rvalue reference
102 using V
= std::variant
<int&&>;
108 assert(Fn::check_call
<int&>(val
));
110 assert(Fn::check_call
<int&>(val
));
111 std::move(v
).visit(obj
);
112 assert(Fn::check_call
<int&&>(val
));
113 std::move(cv
).visit(obj
);
114 assert(Fn::check_call
<int&&>(val
));
119 void test_return_type() {
120 using Fn
= ForwardingCallObject
;
122 const Fn
& cobj
= obj
;
124 { // test call operator forwarding - single variant, single arg
125 using V
= std::variant
<int>;
128 static_assert(std::is_same_v
<decltype(v
.visit(obj
)), Fn
&>);
129 static_assert(std::is_same_v
<decltype(v
.visit(cobj
)), const Fn
&>);
130 static_assert(std::is_same_v
<decltype(v
.visit(std::move(obj
))), Fn
&&>);
131 static_assert(std::is_same_v
<decltype(v
.visit(std::move(cobj
))), const Fn
&&>);
133 { // test call operator forwarding - single variant, multi arg
134 using V
= std::variant
<int, long, double>;
137 static_assert(std::is_same_v
<decltype(v
.visit(obj
)), Fn
&>);
138 static_assert(std::is_same_v
<decltype(v
.visit(cobj
)), const Fn
&>);
139 static_assert(std::is_same_v
<decltype(v
.visit(std::move(obj
))), Fn
&&>);
140 static_assert(std::is_same_v
<decltype(v
.visit(std::move(cobj
))), const Fn
&&>);
144 void test_constexpr() {
145 constexpr ReturnFirst obj
{};
148 using V
= std::variant
<int>;
151 static_assert(v
.visit(obj
) == 42);
154 using V
= std::variant
<short, long, char>;
157 static_assert(v
.visit(obj
) == 42);
161 void test_exceptions() {
162 #ifndef TEST_HAS_NO_EXCEPTIONS
165 auto test
= [&](auto&& v
) {
168 } catch (const std::bad_variant_access
&) {
176 using V
= std::variant
<int, MakeEmptyT
>;
185 // See https://llvm.org/PR31916
186 void test_caller_accepts_nonconst() {
189 void operator()(A
&) {}
196 struct MyVariant
: std::variant
<short, long, float> {};
199 template <std::size_t Index
>
200 void get(const MyVariant
&) {
205 void test_derived_from_variant() {
206 auto v1
= MyVariant
{42};
207 const auto cv1
= MyVariant
{142};
209 v1
.visit([](auto x
) { assert(x
== 42); });
210 cv1
.visit([](auto x
) { assert(x
== 142); });
211 MyVariant
{-1.25f
}.visit([](auto x
) { assert(x
== -1.25f
); });
212 std::move(v1
).visit([](auto x
) { assert(x
== 42); });
213 std::move(cv1
).visit([](auto x
) { assert(x
== 142); });
215 // Check that visit does not take index nor valueless_by_exception members from the base class.
216 struct EvilVariantBase
{
218 char valueless_by_exception
;
221 struct EvilVariant1
: std::variant
<int, long, double>, std::tuple
<int>, EvilVariantBase
{
222 using std::variant
<int, long, double>::variant
;
225 EvilVariant1
{12}.visit([](auto x
) { assert(x
== 12); });
226 EvilVariant1
{12.3}.visit([](auto x
) { assert(x
== 12.3); });
228 // Check that visit unambiguously picks the variant, even if the other base has __impl member.
229 struct ImplVariantBase
{
231 bool operator()() const {
240 struct EvilVariant2
: std::variant
<int, long, double>, ImplVariantBase
{
241 using std::variant
<int, long, double>::variant
;
244 EvilVariant2
{12}.visit([](auto x
) { assert(x
== 12); });
245 EvilVariant2
{12.3}.visit([](auto x
) { assert(x
== 12.3); });
248 int main(int, char**) {
249 test_call_operator_forwarding();
250 test_argument_forwarding();
254 test_caller_accepts_nonconst();
255 test_derived_from_variant();