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
12 // template <class Visitor, class... Variants>
13 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
18 #include <type_traits>
22 #include "test_macros.h"
23 #include "variant_test_helpers.h"
25 void test_call_operator_forwarding() {
26 using Fn
= ForwardingCallObject
;
29 { // test call operator forwarding - no variant
31 assert(Fn::check_call
<>(CT_NonConst
| CT_LValue
));
33 assert(Fn::check_call
<>(CT_Const
| CT_LValue
));
34 std::visit(std::move(obj
));
35 assert(Fn::check_call
<>(CT_NonConst
| CT_RValue
));
36 std::visit(std::move(cobj
));
37 assert(Fn::check_call
<>(CT_Const
| CT_RValue
));
39 { // test call operator forwarding - single variant, single arg
40 using V
= std::variant
<int>;
43 assert(Fn::check_call
<int &>(CT_NonConst
| CT_LValue
));
45 assert(Fn::check_call
<int &>(CT_Const
| CT_LValue
));
46 std::visit(std::move(obj
), v
);
47 assert(Fn::check_call
<int &>(CT_NonConst
| CT_RValue
));
48 std::visit(std::move(cobj
), v
);
49 assert(Fn::check_call
<int &>(CT_Const
| CT_RValue
));
51 { // test call operator forwarding - single variant, multi arg
52 using V
= std::variant
<int, long, double>;
55 assert(Fn::check_call
<long &>(CT_NonConst
| CT_LValue
));
57 assert(Fn::check_call
<long &>(CT_Const
| CT_LValue
));
58 std::visit(std::move(obj
), v
);
59 assert(Fn::check_call
<long &>(CT_NonConst
| CT_RValue
));
60 std::visit(std::move(cobj
), v
);
61 assert(Fn::check_call
<long &>(CT_Const
| CT_RValue
));
63 { // test call operator forwarding - multi variant, multi arg
64 using V
= std::variant
<int, long, double>;
65 using V2
= std::variant
<int *, std::string
>;
68 std::visit(obj
, v
, v2
);
69 assert((Fn::check_call
<long &, std::string
&>(CT_NonConst
| CT_LValue
)));
70 std::visit(cobj
, v
, v2
);
71 assert((Fn::check_call
<long &, std::string
&>(CT_Const
| CT_LValue
)));
72 std::visit(std::move(obj
), v
, v2
);
73 assert((Fn::check_call
<long &, std::string
&>(CT_NonConst
| CT_RValue
)));
74 std::visit(std::move(cobj
), v
, v2
);
75 assert((Fn::check_call
<long &, std::string
&>(CT_Const
| CT_RValue
)));
78 using V
= std::variant
<int, long, double, std::string
>;
79 V
v1(42l), v2("hello"), v3(101), v4(1.1);
80 std::visit(obj
, v1
, v2
, v3
, v4
);
81 assert((Fn::check_call
<long &, std::string
&, int &, double &>(CT_NonConst
| CT_LValue
)));
82 std::visit(cobj
, v1
, v2
, v3
, v4
);
83 assert((Fn::check_call
<long &, std::string
&, int &, double &>(CT_Const
| CT_LValue
)));
84 std::visit(std::move(obj
), v1
, v2
, v3
, v4
);
85 assert((Fn::check_call
<long &, std::string
&, int &, double &>(CT_NonConst
| CT_RValue
)));
86 std::visit(std::move(cobj
), v1
, v2
, v3
, v4
);
87 assert((Fn::check_call
<long &, std::string
&, int &, double &>(CT_Const
| CT_RValue
)));
90 using V
= std::variant
<int, long, double, int*, std::string
>;
91 V
v1(42l), v2("hello"), v3(nullptr), v4(1.1);
92 std::visit(obj
, v1
, v2
, v3
, v4
);
93 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(CT_NonConst
| CT_LValue
)));
94 std::visit(cobj
, v1
, v2
, v3
, v4
);
95 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(CT_Const
| CT_LValue
)));
96 std::visit(std::move(obj
), v1
, v2
, v3
, v4
);
97 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(CT_NonConst
| CT_RValue
)));
98 std::visit(std::move(cobj
), v1
, v2
, v3
, v4
);
99 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(CT_Const
| CT_RValue
)));
103 void test_argument_forwarding() {
104 using Fn
= ForwardingCallObject
;
106 const auto Val
= CT_LValue
| CT_NonConst
;
107 { // single argument - value type
108 using V
= std::variant
<int>;
112 assert(Fn::check_call
<int &>(Val
));
114 assert(Fn::check_call
<const int &>(Val
));
115 std::visit(obj
, std::move(v
));
116 assert(Fn::check_call
<int &&>(Val
));
117 std::visit(obj
, std::move(cv
));
118 assert(Fn::check_call
<const int &&>(Val
));
120 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
121 { // single argument - lvalue reference
122 using V
= std::variant
<int &>;
127 assert(Fn::check_call
<int &>(Val
));
129 assert(Fn::check_call
<int &>(Val
));
130 std::visit(obj
, std::move(v
));
131 assert(Fn::check_call
<int &>(Val
));
132 std::visit(obj
, std::move(cv
));
133 assert(Fn::check_call
<int &>(Val
));
135 { // single argument - rvalue reference
136 using V
= std::variant
<int &&>;
141 assert(Fn::check_call
<int &>(Val
));
143 assert(Fn::check_call
<int &>(Val
));
144 std::visit(obj
, std::move(v
));
145 assert(Fn::check_call
<int &&>(Val
));
146 std::visit(obj
, std::move(cv
));
147 assert(Fn::check_call
<int &&>(Val
));
150 { // multi argument - multi variant
151 using V
= std::variant
<int, std::string
, long>;
152 V
v1(42), v2("hello"), v3(43l);
153 std::visit(obj
, v1
, v2
, v3
);
154 assert((Fn::check_call
<int &, std::string
&, long &>(Val
)));
155 std::visit(obj
, std::as_const(v1
), std::as_const(v2
), std::move(v3
));
156 assert((Fn::check_call
<const int &, const std::string
&, long &&>(Val
)));
159 using V
= std::variant
<int, long, double, std::string
>;
160 V
v1(42l), v2("hello"), v3(101), v4(1.1);
161 std::visit(obj
, v1
, v2
, v3
, v4
);
162 assert((Fn::check_call
<long &, std::string
&, int &, double &>(Val
)));
163 std::visit(obj
, std::as_const(v1
), std::as_const(v2
), std::move(v3
), std::move(v4
));
164 assert((Fn::check_call
<const long &, const std::string
&, int &&, double &&>(Val
)));
167 using V
= std::variant
<int, long, double, int*, std::string
>;
168 V
v1(42l), v2("hello"), v3(nullptr), v4(1.1);
169 std::visit(obj
, v1
, v2
, v3
, v4
);
170 assert((Fn::check_call
<long &, std::string
&, int *&, double &>(Val
)));
171 std::visit(obj
, std::as_const(v1
), std::as_const(v2
), std::move(v3
), std::move(v4
));
172 assert((Fn::check_call
<const long &, const std::string
&, int *&&, double &&>(Val
)));
176 void test_return_type() {
177 using Fn
= ForwardingCallObject
;
179 const Fn
&cobj
= obj
;
180 { // test call operator forwarding - no variant
181 static_assert(std::is_same_v
<decltype(std::visit(obj
)), Fn
&>);
182 static_assert(std::is_same_v
<decltype(std::visit(cobj
)), const Fn
&>);
183 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
))), Fn
&&>);
184 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
))), const Fn
&&>);
186 { // test call operator forwarding - single variant, single arg
187 using V
= std::variant
<int>;
189 static_assert(std::is_same_v
<decltype(std::visit(obj
, v
)), Fn
&>);
190 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v
)), const Fn
&>);
191 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v
)), Fn
&&>);
192 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v
)), const Fn
&&>);
194 { // test call operator forwarding - single variant, multi arg
195 using V
= std::variant
<int, long, double>;
197 static_assert(std::is_same_v
<decltype(std::visit(obj
, v
)), Fn
&>);
198 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v
)), const Fn
&>);
199 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v
)), Fn
&&>);
200 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v
)), const Fn
&&>);
202 { // test call operator forwarding - multi variant, multi arg
203 using V
= std::variant
<int, long, double>;
204 using V2
= std::variant
<int *, std::string
>;
207 static_assert(std::is_same_v
<decltype(std::visit(obj
, v
, v2
)), Fn
&>);
208 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v
, v2
)), const Fn
&>);
209 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v
, v2
)), Fn
&&>);
210 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v
, v2
)), const Fn
&&>);
213 using V
= std::variant
<int, long, double, std::string
>;
214 V
v1(42l), v2("hello"), v3(101), v4(1.1);
215 static_assert(std::is_same_v
<decltype(std::visit(obj
, v1
, v2
, v3
, v4
)), Fn
&>);
216 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v1
, v2
, v3
, v4
)), const Fn
&>);
217 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v1
, v2
, v3
, v4
)), Fn
&&>);
218 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v1
, v2
, v3
, v4
)), const Fn
&&>);
221 using V
= std::variant
<int, long, double, int*, std::string
>;
222 V
v1(42l), v2("hello"), v3(nullptr), v4(1.1);
223 static_assert(std::is_same_v
<decltype(std::visit(obj
, v1
, v2
, v3
, v4
)), Fn
&>);
224 static_assert(std::is_same_v
<decltype(std::visit(cobj
, v1
, v2
, v3
, v4
)), const Fn
&>);
225 static_assert(std::is_same_v
<decltype(std::visit(std::move(obj
), v1
, v2
, v3
, v4
)), Fn
&&>);
226 static_assert(std::is_same_v
<decltype(std::visit(std::move(cobj
), v1
, v2
, v3
, v4
)), const Fn
&&>);
230 void test_constexpr() {
231 constexpr ReturnFirst obj
{};
232 constexpr ReturnArity aobj
{};
234 using V
= std::variant
<int>;
236 static_assert(std::visit(obj
, v
) == 42, "");
239 using V
= std::variant
<short, long, char>;
241 static_assert(std::visit(obj
, v
) == 42, "");
244 using V1
= std::variant
<int>;
245 using V2
= std::variant
<int, char *, long long>;
246 using V3
= std::variant
<bool, int, int>;
248 constexpr V2
v2(nullptr);
250 static_assert(std::visit(aobj
, v1
, v2
, v3
) == 3, "");
253 using V1
= std::variant
<int>;
254 using V2
= std::variant
<int, char *, long long>;
255 using V3
= std::variant
<void *, int, int>;
257 constexpr V2
v2(nullptr);
259 static_assert(std::visit(aobj
, v1
, v2
, v3
) == 3, "");
262 using V
= std::variant
<int, long, double, int *>;
263 constexpr V
v1(42l), v2(101), v3(nullptr), v4(1.1);
264 static_assert(std::visit(aobj
, v1
, v2
, v3
, v4
) == 4, "");
267 using V
= std::variant
<int, long, double, long long, int *>;
268 constexpr V
v1(42l), v2(101), v3(nullptr), v4(1.1);
269 static_assert(std::visit(aobj
, v1
, v2
, v3
, v4
) == 4, "");
273 void test_exceptions() {
274 #ifndef TEST_HAS_NO_EXCEPTIONS
276 auto test
= [&](auto &&... args
) {
278 std::visit(obj
, args
...);
279 } catch (const std::bad_variant_access
&) {
286 using V
= std::variant
<int, MakeEmptyT
>;
292 using V
= std::variant
<int, MakeEmptyT
>;
293 using V2
= std::variant
<long, std::string
, void *>;
300 using V
= std::variant
<int, MakeEmptyT
>;
301 using V2
= std::variant
<long, std::string
, void *>;
308 using V
= std::variant
<int, MakeEmptyT
>;
309 using V2
= std::variant
<long, std::string
, void *, MakeEmptyT
>;
317 using V
= std::variant
<int, long, double, MakeEmptyT
>;
318 V
v1(42l), v2(101), v3(202), v4(1.1);
320 assert(test(v1
, v2
, v3
, v4
));
323 using V
= std::variant
<int, long, double, long long, MakeEmptyT
>;
324 V
v1(42l), v2(101), v3(202), v4(1.1);
329 assert(test(v1
, v2
, v3
, v4
));
334 // See https://llvm.org/PR31916
335 void test_caller_accepts_nonconst() {
338 void operator()(A
&) {}
341 std::visit(Visitor
{}, v
);
344 struct MyVariant
: std::variant
<short, long, float> {};
347 template <std::size_t Index
>
348 void get(const MyVariant
&) {
353 void test_derived_from_variant() {
354 auto v1
= MyVariant
{42};
355 const auto cv1
= MyVariant
{142};
356 std::visit([](auto x
) { assert(x
== 42); }, v1
);
357 std::visit([](auto x
) { assert(x
== 142); }, cv1
);
358 std::visit([](auto x
) { assert(x
== -1.25f
); }, MyVariant
{-1.25f
});
359 std::visit([](auto x
) { assert(x
== 42); }, std::move(v1
));
360 std::visit([](auto x
) { assert(x
== 142); }, std::move(cv1
));
362 // Check that visit does not take index nor valueless_by_exception members from the base class.
363 struct EvilVariantBase
{
365 char valueless_by_exception
;
368 struct EvilVariant1
: std::variant
<int, long, double>,
371 using std::variant
<int, long, double>::variant
;
374 std::visit([](auto x
) { assert(x
== 12); }, EvilVariant1
{12});
375 std::visit([](auto x
) { assert(x
== 12.3); }, EvilVariant1
{12.3});
377 // Check that visit unambiguously picks the variant, even if the other base has __impl member.
378 struct ImplVariantBase
{
380 bool operator()() const { assert(false); return false; }
386 struct EvilVariant2
: std::variant
<int, long, double>, ImplVariantBase
{
387 using std::variant
<int, long, double>::variant
;
390 std::visit([](auto x
) { assert(x
== 12); }, EvilVariant2
{12});
391 std::visit([](auto x
) { assert(x
== 12.3); }, EvilVariant2
{12.3});
395 template <typename T
>
396 void operator()(const T
&) const {}
399 template <typename T
, typename
= decltype(std::visit(
400 std::declval
<any_visitor
&>(), std::declval
<T
>()))>
401 constexpr bool has_visit(int) {
405 template <typename T
>
406 constexpr bool has_visit(...) {
411 struct BadVariant
: std::variant
<short>, std::variant
<long, float> {};
412 struct BadVariant2
: private std::variant
<long, float> {};
413 struct GoodVariant
: std::variant
<long, float> {};
414 struct GoodVariant2
: GoodVariant
{};
416 static_assert(!has_visit
<int>(0));
417 static_assert(!has_visit
<BadVariant
>(0));
418 static_assert(!has_visit
<BadVariant2
>(0));
419 static_assert(has_visit
<std::variant
<int>>(0));
420 static_assert(has_visit
<GoodVariant
>(0));
421 static_assert(has_visit
<GoodVariant2
>(0));
424 int main(int, char**) {
425 test_call_operator_forwarding();
426 test_argument_forwarding();
430 test_caller_accepts_nonconst();
431 test_derived_from_variant();