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
11 // XFAIL: availability-bad_variant_access-missing && !no-exceptions
14 // template <class Visitor, class... Variants>
15 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
20 #include <type_traits>
24 #include "test_macros.h"
25 #include "variant_test_helpers.h"
27 void test_call_operator_forwarding() {
28 using Fn
= ForwardingCallObject
;
31 { // test call operator forwarding - no variant
33 assert(Fn::check_call
<>(CT_NonConst
| CT_LValue
));
35 assert(Fn::check_call
<>(CT_Const
| CT_LValue
));
36 std::visit(std::move(obj
));
37 assert(Fn::check_call
<>(CT_NonConst
| CT_RValue
));
38 std::visit(std::move(cobj
));
39 assert(Fn::check_call
<>(CT_Const
| CT_RValue
));
41 { // test call operator forwarding - single variant, single arg
42 using V
= std::variant
<int>;
45 assert(Fn::check_call
<int &>(CT_NonConst
| CT_LValue
));
47 assert(Fn::check_call
<int &>(CT_Const
| CT_LValue
));
48 std::visit(std::move(obj
), v
);
49 assert(Fn::check_call
<int &>(CT_NonConst
| CT_RValue
));
50 std::visit(std::move(cobj
), v
);
51 assert(Fn::check_call
<int &>(CT_Const
| CT_RValue
));
53 { // test call operator forwarding - single variant, multi arg
54 using V
= std::variant
<int, long, double>;
57 assert(Fn::check_call
<long &>(CT_NonConst
| CT_LValue
));
59 assert(Fn::check_call
<long &>(CT_Const
| CT_LValue
));
60 std::visit(std::move(obj
), v
);
61 assert(Fn::check_call
<long &>(CT_NonConst
| CT_RValue
));
62 std::visit(std::move(cobj
), v
);
63 assert(Fn::check_call
<long &>(CT_Const
| CT_RValue
));
65 { // test call operator forwarding - multi variant, multi arg
66 using V
= std::variant
<int, long, double>;
67 using V2
= std::variant
<int *, std::string
>;
70 std::visit(obj
, v
, v2
);
71 assert((Fn::check_call
<long &, std::string
&>(CT_NonConst
| CT_LValue
)));
72 std::visit(cobj
, v
, v2
);
73 assert((Fn::check_call
<long &, std::string
&>(CT_Const
| CT_LValue
)));
74 std::visit(std::move(obj
), v
, v2
);
75 assert((Fn::check_call
<long &, std::string
&>(CT_NonConst
| CT_RValue
)));
76 std::visit(std::move(cobj
), v
, v2
);
77 assert((Fn::check_call
<long &, std::string
&>(CT_Const
| CT_RValue
)));
80 using V
= std::variant
<int, long, double, std::string
>;
81 V
v1(42l), v2("hello"), v3(101), v4(1.1);
82 std::visit(obj
, v1
, v2
, v3
, v4
);
83 assert((Fn::check_call
<long &, std::string
&, int &, double &>(CT_NonConst
| CT_LValue
)));
84 std::visit(cobj
, v1
, v2
, v3
, v4
);
85 assert((Fn::check_call
<long &, std::string
&, int &, double &>(CT_Const
| CT_LValue
)));
86 std::visit(std::move(obj
), v1
, v2
, v3
, v4
);
87 assert((Fn::check_call
<long &, std::string
&, int &, double &>(CT_NonConst
| CT_RValue
)));
88 std::visit(std::move(cobj
), v1
, v2
, v3
, v4
);
89 assert((Fn::check_call
<long &, std::string
&, int &, double &>(CT_Const
| CT_RValue
)));
92 using V
= std::variant
<int, long, double, int*, std::string
>;
93 V
v1(42l), v2("hello"), v3(nullptr), v4(1.1);
94 std::visit(obj
, v1
, v2
, v3
, v4
);
95 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(CT_NonConst
| CT_LValue
)));
96 std::visit(cobj
, v1
, v2
, v3
, v4
);
97 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(CT_Const
| CT_LValue
)));
98 std::visit(std::move(obj
), v1
, v2
, v3
, v4
);
99 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(CT_NonConst
| CT_RValue
)));
100 std::visit(std::move(cobj
), v1
, v2
, v3
, v4
);
101 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(CT_Const
| CT_RValue
)));
105 void test_argument_forwarding() {
106 using Fn
= ForwardingCallObject
;
108 const auto Val
= CT_LValue
| CT_NonConst
;
109 { // single argument - value type
110 using V
= std::variant
<int>;
114 assert(Fn::check_call
<int &>(Val
));
116 assert(Fn::check_call
<const int &>(Val
));
117 std::visit(obj
, std::move(v
));
118 assert(Fn::check_call
<int &&>(Val
));
119 std::visit(obj
, std::move(cv
));
120 assert(Fn::check_call
<const int &&>(Val
));
122 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
123 { // single argument - lvalue reference
124 using V
= std::variant
<int &>;
129 assert(Fn::check_call
<int &>(Val
));
131 assert(Fn::check_call
<int &>(Val
));
132 std::visit(obj
, std::move(v
));
133 assert(Fn::check_call
<int &>(Val
));
134 std::visit(obj
, std::move(cv
));
135 assert(Fn::check_call
<int &>(Val
));
137 { // single argument - rvalue reference
138 using V
= std::variant
<int &&>;
143 assert(Fn::check_call
<int &>(Val
));
145 assert(Fn::check_call
<int &>(Val
));
146 std::visit(obj
, std::move(v
));
147 assert(Fn::check_call
<int &&>(Val
));
148 std::visit(obj
, std::move(cv
));
149 assert(Fn::check_call
<int &&>(Val
));
152 { // multi argument - multi variant
153 using V
= std::variant
<int, std::string
, long>;
154 V
v1(42), v2("hello"), v3(43l);
155 std::visit(obj
, v1
, v2
, v3
);
156 assert((Fn::check_call
<int &, std::string
&, long &>(Val
)));
157 std::visit(obj
, std::as_const(v1
), std::as_const(v2
), std::move(v3
));
158 assert((Fn::check_call
<const int &, const std::string
&, long &&>(Val
)));
161 using V
= std::variant
<int, long, double, std::string
>;
162 V
v1(42l), v2("hello"), v3(101), v4(1.1);
163 std::visit(obj
, v1
, v2
, v3
, v4
);
164 assert((Fn::check_call
<long &, std::string
&, int &, double &>(Val
)));
165 std::visit(obj
, std::as_const(v1
), std::as_const(v2
), std::move(v3
), std::move(v4
));
166 assert((Fn::check_call
<const long &, const std::string
&, int &&, double &&>(Val
)));
169 using V
= std::variant
<int, long, double, int*, std::string
>;
170 V
v1(42l), v2("hello"), v3(nullptr), v4(1.1);
171 std::visit(obj
, v1
, v2
, v3
, v4
);
172 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(Val
)));
173 std::visit(obj
, std::as_const(v1
), std::as_const(v2
), std::move(v3
), std::move(v4
));
174 assert((Fn::check_call
<const long &, const std::string
&, int *&&, double &&>(Val
)));
178 void test_return_type() {
179 using Fn
= ForwardingCallObject
;
181 const Fn
&cobj
= obj
;
182 { // test call operator forwarding - no variant
183 static_assert(std::is_same_v
<decltype(std::visit(obj
)), Fn
&>);
184 static_assert(std::is_same_v
<decltype(std::visit(cobj
)), const Fn
&>);
185 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
))), Fn
&&>);
186 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
))), const Fn
&&>);
188 { // test call operator forwarding - single variant, single arg
189 using V
= std::variant
<int>;
191 static_assert(std::is_same_v
<decltype(std::visit(obj
, v
)), Fn
&>);
192 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v
)), const Fn
&>);
193 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v
)), Fn
&&>);
194 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v
)), const Fn
&&>);
196 { // test call operator forwarding - single variant, multi arg
197 using V
= std::variant
<int, long, double>;
199 static_assert(std::is_same_v
<decltype(std::visit(obj
, v
)), Fn
&>);
200 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v
)), const Fn
&>);
201 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v
)), Fn
&&>);
202 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v
)), const Fn
&&>);
204 { // test call operator forwarding - multi variant, multi arg
205 using V
= std::variant
<int, long, double>;
206 using V2
= std::variant
<int *, std::string
>;
209 static_assert(std::is_same_v
<decltype(std::visit(obj
, v
, v2
)), Fn
&>);
210 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v
, v2
)), const Fn
&>);
211 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v
, v2
)), Fn
&&>);
212 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v
, v2
)), const Fn
&&>);
215 using V
= std::variant
<int, long, double, std::string
>;
216 V
v1(42l), v2("hello"), v3(101), v4(1.1);
217 static_assert(std::is_same_v
<decltype(std::visit(obj
, v1
, v2
, v3
, v4
)), Fn
&>);
218 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v1
, v2
, v3
, v4
)), const Fn
&>);
219 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v1
, v2
, v3
, v4
)), Fn
&&>);
220 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v1
, v2
, v3
, v4
)), const Fn
&&>);
223 using V
= std::variant
<int, long, double, int*, std::string
>;
224 V
v1(42l), v2("hello"), v3(nullptr), v4(1.1);
225 static_assert(std::is_same_v
<decltype(std::visit(obj
, v1
, v2
, v3
, v4
)), Fn
&>);
226 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v1
, v2
, v3
, v4
)), const Fn
&>);
227 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v1
, v2
, v3
, v4
)), Fn
&&>);
228 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v1
, v2
, v3
, v4
)), const Fn
&&>);
232 void test_constexpr() {
233 constexpr ReturnFirst obj
{};
234 constexpr ReturnArity aobj
{};
236 using V
= std::variant
<int>;
238 static_assert(std::visit(obj
, v
) == 42, "");
241 using V
= std::variant
<short, long, char>;
243 static_assert(std::visit(obj
, v
) == 42, "");
246 using V1
= std::variant
<int>;
247 using V2
= std::variant
<int, char *, long long>;
248 using V3
= std::variant
<bool, int, int>;
250 constexpr V2
v2(nullptr);
252 static_assert(std::visit(aobj
, v1
, v2
, v3
) == 3, "");
255 using V1
= std::variant
<int>;
256 using V2
= std::variant
<int, char *, long long>;
257 using V3
= std::variant
<void *, int, int>;
259 constexpr V2
v2(nullptr);
261 static_assert(std::visit(aobj
, v1
, v2
, v3
) == 3, "");
264 using V
= std::variant
<int, long, double, int *>;
265 constexpr V
v1(42l), v2(101), v3(nullptr), v4(1.1);
266 static_assert(std::visit(aobj
, v1
, v2
, v3
, v4
) == 4, "");
269 using V
= std::variant
<int, long, double, long long, int *>;
270 constexpr V
v1(42l), v2(101), v3(nullptr), v4(1.1);
271 static_assert(std::visit(aobj
, v1
, v2
, v3
, v4
) == 4, "");
275 void test_exceptions() {
276 #ifndef TEST_HAS_NO_EXCEPTIONS
278 auto test
= [&](auto &&... args
) {
280 std::visit(obj
, args
...);
281 } catch (const std::bad_variant_access
&) {
288 using V
= std::variant
<int, MakeEmptyT
>;
294 using V
= std::variant
<int, MakeEmptyT
>;
295 using V2
= std::variant
<long, std::string
, void *>;
302 using V
= std::variant
<int, MakeEmptyT
>;
303 using V2
= std::variant
<long, std::string
, void *>;
310 using V
= std::variant
<int, MakeEmptyT
>;
311 using V2
= std::variant
<long, std::string
, void *, MakeEmptyT
>;
319 using V
= std::variant
<int, long, double, MakeEmptyT
>;
320 V
v1(42l), v2(101), v3(202), v4(1.1);
322 assert(test(v1
, v2
, v3
, v4
));
325 using V
= std::variant
<int, long, double, long long, MakeEmptyT
>;
326 V
v1(42l), v2(101), v3(202), v4(1.1);
331 assert(test(v1
, v2
, v3
, v4
));
336 // See https://llvm.org/PR31916
337 void test_caller_accepts_nonconst() {
340 void operator()(A
&) {}
343 std::visit(Visitor
{}, v
);
346 struct MyVariant
: std::variant
<short, long, float> {};
349 template <std::size_t Index
>
350 void get(const MyVariant
&) {
355 void test_derived_from_variant() {
356 auto v1
= MyVariant
{42};
357 const auto cv1
= MyVariant
{142};
358 std::visit([](auto x
) { assert(x
== 42); }, v1
);
359 std::visit([](auto x
) { assert(x
== 142); }, cv1
);
360 std::visit([](auto x
) { assert(x
== -1.25f
); }, MyVariant
{-1.25f
});
361 std::visit([](auto x
) { assert(x
== 42); }, std::move(v1
));
362 std::visit([](auto x
) { assert(x
== 142); }, std::move(cv1
));
364 // Check that visit does not take index nor valueless_by_exception members from the base class.
365 struct EvilVariantBase
{
367 char valueless_by_exception
;
370 struct EvilVariant1
: std::variant
<int, long, double>,
373 using std::variant
<int, long, double>::variant
;
376 std::visit([](auto x
) { assert(x
== 12); }, EvilVariant1
{12});
377 std::visit([](auto x
) { assert(x
== 12.3); }, EvilVariant1
{12.3});
379 // Check that visit unambiguously picks the variant, even if the other base has __impl member.
380 struct ImplVariantBase
{
382 bool operator()() const { assert(false); return false; }
388 struct EvilVariant2
: std::variant
<int, long, double>, ImplVariantBase
{
389 using std::variant
<int, long, double>::variant
;
392 std::visit([](auto x
) { assert(x
== 12); }, EvilVariant2
{12});
393 std::visit([](auto x
) { assert(x
== 12.3); }, EvilVariant2
{12.3});
397 template <typename T
>
398 void operator()(const T
&) const {}
401 template <typename T
, typename
= decltype(std::visit(
402 std::declval
<any_visitor
&>(), std::declval
<T
>()))>
403 constexpr bool has_visit(int) {
407 template <typename T
>
408 constexpr bool has_visit(...) {
413 struct BadVariant
: std::variant
<short>, std::variant
<long, float> {};
414 struct BadVariant2
: private std::variant
<long, float> {};
415 struct GoodVariant
: std::variant
<long, float> {};
416 struct GoodVariant2
: GoodVariant
{};
418 static_assert(!has_visit
<int>(0));
419 static_assert(!has_visit
<BadVariant
>(0));
420 static_assert(!has_visit
<BadVariant2
>(0));
421 static_assert(has_visit
<std::variant
<int>>(0));
422 static_assert(has_visit
<GoodVariant
>(0));
423 static_assert(has_visit
<GoodVariant2
>(0));
426 int main(int, char**) {
427 test_call_operator_forwarding();
428 test_argument_forwarding();
432 test_caller_accepts_nonconst();
433 test_derived_from_variant();