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 10 11 // <variant> 12 // template <class Visitor, class... Variants> 13 // constexpr see below visit(Visitor&& vis, Variants&&... vars); 14 15 #include <cassert> 16 #include <memory> 17 #include <string> 18 #include <tuple> 19 #include <type_traits> 20 #include <utility> 21 #include <variant> 22 23 #include "test_macros.h" 24 #include "variant_test_helpers.h" 25 26 void test_call_operator_forwarding() { 27 using Fn = ForwardingCallObject; 28 Fn obj{}; 29 const Fn &cobj = obj; 30 { // test call operator forwarding - no variant 31 std::visit(obj); 32 assert(Fn::check_call<>(CT_NonConst | CT_LValue)); 33 std::visit(cobj); 34 assert(Fn::check_call<>(CT_Const | CT_LValue)); 35 std::visit(std::move(obj)); 36 assert(Fn::check_call<>(CT_NonConst | CT_RValue)); 37 std::visit(std::move(cobj)); 38 assert(Fn::check_call<>(CT_Const | CT_RValue)); 39 } 40 { // test call operator forwarding - single variant, single arg 41 using V = std::variant<int>; 42 V v(42); 43 std::visit(obj, v); 44 assert(Fn::check_call<int &>(CT_NonConst | CT_LValue)); 45 std::visit(cobj, v); 46 assert(Fn::check_call<int &>(CT_Const | CT_LValue)); 47 std::visit(std::move(obj), v); 48 assert(Fn::check_call<int &>(CT_NonConst | CT_RValue)); 49 std::visit(std::move(cobj), v); 50 assert(Fn::check_call<int &>(CT_Const | CT_RValue)); 51 } 52 { // test call operator forwarding - single variant, multi arg 53 using V = std::variant<int, long, double>; 54 V v(42l); 55 std::visit(obj, v); 56 assert(Fn::check_call<long &>(CT_NonConst | CT_LValue)); 57 std::visit(cobj, v); 58 assert(Fn::check_call<long &>(CT_Const | CT_LValue)); 59 std::visit(std::move(obj), v); 60 assert(Fn::check_call<long &>(CT_NonConst | CT_RValue)); 61 std::visit(std::move(cobj), v); 62 assert(Fn::check_call<long &>(CT_Const | CT_RValue)); 63 } 64 { // test call operator forwarding - multi variant, multi arg 65 using V = std::variant<int, long, double>; 66 using V2 = std::variant<int *, std::string>; 67 V v(42l); 68 V2 v2("hello"); 69 std::visit(obj, v, v2); 70 assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue))); 71 std::visit(cobj, v, v2); 72 assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue))); 73 std::visit(std::move(obj), v, v2); 74 assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue))); 75 std::visit(std::move(cobj), v, v2); 76 assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue))); 77 } 78 { 79 using V = std::variant<int, long, double, std::string>; 80 V v1(42l), v2("hello"), v3(101), v4(1.1); 81 std::visit(obj, v1, v2, v3, v4); 82 assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue))); 83 std::visit(cobj, v1, v2, v3, v4); 84 assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue))); 85 std::visit(std::move(obj), v1, v2, v3, v4); 86 assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue))); 87 std::visit(std::move(cobj), v1, v2, v3, v4); 88 assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue))); 89 } 90 { 91 using V = std::variant<int, long, double, int*, std::string>; 92 V v1(42l), v2("hello"), v3(nullptr), v4(1.1); 93 std::visit(obj, v1, v2, v3, v4); 94 assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue))); 95 std::visit(cobj, v1, v2, v3, v4); 96 assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue))); 97 std::visit(std::move(obj), v1, v2, v3, v4); 98 assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue))); 99 std::visit(std::move(cobj), v1, v2, v3, v4); 100 assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue))); 101 } 102 } 103 104 void test_argument_forwarding() { 105 using Fn = ForwardingCallObject; 106 Fn obj{}; 107 const auto Val = CT_LValue | CT_NonConst; 108 { // single argument - value type 109 using V = std::variant<int>; 110 V v(42); 111 const V &cv = v; 112 std::visit(obj, v); 113 assert(Fn::check_call<int &>(Val)); 114 std::visit(obj, cv); 115 assert(Fn::check_call<const int &>(Val)); 116 std::visit(obj, std::move(v)); 117 assert(Fn::check_call<int &&>(Val)); 118 std::visit(obj, std::move(cv)); 119 assert(Fn::check_call<const int &&>(Val)); 120 } 121 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) 122 { // single argument - lvalue reference 123 using V = std::variant<int &>; 124 int x = 42; 125 V v(x); 126 const V &cv = v; 127 std::visit(obj, v); 128 assert(Fn::check_call<int &>(Val)); 129 std::visit(obj, cv); 130 assert(Fn::check_call<int &>(Val)); 131 std::visit(obj, std::move(v)); 132 assert(Fn::check_call<int &>(Val)); 133 std::visit(obj, std::move(cv)); 134 assert(Fn::check_call<int &>(Val)); 135 } 136 { // single argument - rvalue reference 137 using V = std::variant<int &&>; 138 int x = 42; 139 V v(std::move(x)); 140 const V &cv = v; 141 std::visit(obj, v); 142 assert(Fn::check_call<int &>(Val)); 143 std::visit(obj, cv); 144 assert(Fn::check_call<int &>(Val)); 145 std::visit(obj, std::move(v)); 146 assert(Fn::check_call<int &&>(Val)); 147 std::visit(obj, std::move(cv)); 148 assert(Fn::check_call<int &&>(Val)); 149 } 150 #endif 151 { // multi argument - multi variant 152 using V = std::variant<int, std::string, long>; 153 V v1(42), v2("hello"), v3(43l); 154 std::visit(obj, v1, v2, v3); 155 assert((Fn::check_call<int &, std::string &, long &>(Val))); 156 std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); 157 assert((Fn::check_call<const int &, const std::string &, long &&>(Val))); 158 } 159 { 160 using V = std::variant<int, long, double, std::string>; 161 V v1(42l), v2("hello"), v3(101), v4(1.1); 162 std::visit(obj, v1, v2, v3, v4); 163 assert((Fn::check_call<long &, std::string &, int &, double &>(Val))); 164 std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); 165 assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val))); 166 } 167 { 168 using V = std::variant<int, long, double, int*, std::string>; 169 V v1(42l), v2("hello"), v3(nullptr), v4(1.1); 170 std::visit(obj, v1, v2, v3, v4); 171 assert((Fn::check_call<long &, std::string &, int *&, double &>(Val))); 172 std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); 173 assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val))); 174 } 175 } 176 177 void test_return_type() { 178 using Fn = ForwardingCallObject; 179 Fn obj{}; 180 const Fn &cobj = obj; 181 { // test call operator forwarding - no variant 182 static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>); 183 static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>); 184 static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>); 185 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>); 186 } 187 { // test call operator forwarding - single variant, single arg 188 using V = std::variant<int>; 189 V v(42); 190 static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>); 191 static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>); 192 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>); 193 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>); 194 } 195 { // test call operator forwarding - single variant, multi arg 196 using V = std::variant<int, long, double>; 197 V v(42l); 198 static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>); 199 static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>); 200 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>); 201 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>); 202 } 203 { // test call operator forwarding - multi variant, multi arg 204 using V = std::variant<int, long, double>; 205 using V2 = std::variant<int *, std::string>; 206 V v(42l); 207 V2 v2("hello"); 208 static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>); 209 static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>); 210 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>); 211 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>); 212 } 213 { 214 using V = std::variant<int, long, double, std::string>; 215 V v1(42l), v2("hello"), v3(101), v4(1.1); 216 static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>); 217 static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>); 218 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>); 219 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>); 220 } 221 { 222 using V = std::variant<int, long, double, int*, std::string>; 223 V v1(42l), v2("hello"), v3(nullptr), v4(1.1); 224 static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>); 225 static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>); 226 static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>); 227 static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>); 228 } 229 } 230 231 void test_constexpr() { 232 constexpr ReturnFirst obj{}; 233 constexpr ReturnArity aobj{}; 234 { 235 using V = std::variant<int>; 236 constexpr V v(42); 237 static_assert(std::visit(obj, v) == 42, ""); 238 } 239 { 240 using V = std::variant<short, long, char>; 241 constexpr V v(42l); 242 static_assert(std::visit(obj, v) == 42, ""); 243 } 244 { 245 using V1 = std::variant<int>; 246 using V2 = std::variant<int, char *, long long>; 247 using V3 = std::variant<bool, int, int>; 248 constexpr V1 v1; 249 constexpr V2 v2(nullptr); 250 constexpr V3 v3; 251 static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); 252 } 253 { 254 using V1 = std::variant<int>; 255 using V2 = std::variant<int, char *, long long>; 256 using V3 = std::variant<void *, int, int>; 257 constexpr V1 v1; 258 constexpr V2 v2(nullptr); 259 constexpr V3 v3; 260 static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); 261 } 262 { 263 using V = std::variant<int, long, double, int *>; 264 constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); 265 static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); 266 } 267 { 268 using V = std::variant<int, long, double, long long, int *>; 269 constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); 270 static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); 271 } 272 } 273 274 void test_exceptions() { 275 #ifndef TEST_HAS_NO_EXCEPTIONS 276 ReturnArity obj{}; 277 auto test = [&](auto &&... args) { 278 try { 279 std::visit(obj, args...); 280 } catch (const std::bad_variant_access &) { 281 return true; 282 } catch (...) { 283 } 284 return false; 285 }; 286 { 287 using V = std::variant<int, MakeEmptyT>; 288 V v; 289 makeEmpty(v); 290 assert(test(v)); 291 } 292 { 293 using V = std::variant<int, MakeEmptyT>; 294 using V2 = std::variant<long, std::string, void *>; 295 V v; 296 makeEmpty(v); 297 V2 v2("hello"); 298 assert(test(v, v2)); 299 } 300 { 301 using V = std::variant<int, MakeEmptyT>; 302 using V2 = std::variant<long, std::string, void *>; 303 V v; 304 makeEmpty(v); 305 V2 v2("hello"); 306 assert(test(v2, v)); 307 } 308 { 309 using V = std::variant<int, MakeEmptyT>; 310 using V2 = std::variant<long, std::string, void *, MakeEmptyT>; 311 V v; 312 makeEmpty(v); 313 V2 v2; 314 makeEmpty(v2); 315 assert(test(v, v2)); 316 } 317 { 318 using V = std::variant<int, long, double, MakeEmptyT>; 319 V v1(42l), v2(101), v3(202), v4(1.1); 320 makeEmpty(v1); 321 assert(test(v1, v2, v3, v4)); 322 } 323 { 324 using V = std::variant<int, long, double, long long, MakeEmptyT>; 325 V v1(42l), v2(101), v3(202), v4(1.1); 326 makeEmpty(v1); 327 makeEmpty(v2); 328 makeEmpty(v3); 329 makeEmpty(v4); 330 assert(test(v1, v2, v3, v4)); 331 } 332 #endif 333 } 334 335 // See https://llvm.org/PR31916 336 void test_caller_accepts_nonconst() { 337 struct A {}; 338 struct Visitor { 339 void operator()(A&) {} 340 }; 341 std::variant<A> v; 342 std::visit(Visitor{}, v); 343 } 344 345 struct MyVariant : std::variant<short, long, float> {}; 346 347 namespace std { 348 template <std::size_t Index> 349 void get(const MyVariant&) { 350 assert(false); 351 } 352 } // namespace std 353 354 void test_derived_from_variant() { 355 auto v1 = MyVariant{42}; 356 const auto cv1 = MyVariant{142}; 357 std::visit([](auto x) { assert(x == 42); }, v1); 358 std::visit([](auto x) { assert(x == 142); }, cv1); 359 std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f}); 360 std::visit([](auto x) { assert(x == 42); }, std::move(v1)); 361 std::visit([](auto x) { assert(x == 142); }, std::move(cv1)); 362 363 // Check that visit does not take index nor valueless_by_exception members from the base class. 364 struct EvilVariantBase { 365 int index; 366 char valueless_by_exception; 367 }; 368 369 struct EvilVariant1 : std::variant<int, long, double>, 370 std::tuple<int>, 371 EvilVariantBase { 372 using std::variant<int, long, double>::variant; 373 }; 374 375 std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); 376 std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); 377 378 // Check that visit unambiguously picks the variant, even if the other base has __impl member. 379 struct ImplVariantBase { 380 struct Callable { 381 bool operator()() const { assert(false); return false; } 382 }; 383 384 Callable __impl; 385 }; 386 387 struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase { 388 using std::variant<int, long, double>::variant; 389 }; 390 391 std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); 392 std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3}); 393 } 394 395 struct any_visitor { 396 template <typename T> 397 void operator()(const T&) const {} 398 }; 399 400 template <typename T, typename = decltype(std::visit( 401 std::declval<any_visitor&>(), std::declval<T>()))> 402 constexpr bool has_visit(int) { 403 return true; 404 } 405 406 template <typename T> 407 constexpr bool has_visit(...) { 408 return false; 409 } 410 411 void test_sfinae() { 412 struct BadVariant : std::variant<short>, std::variant<long, float> {}; 413 struct BadVariant2 : private std::variant<long, float> {}; 414 struct GoodVariant : std::variant<long, float> {}; 415 struct GoodVariant2 : GoodVariant {}; 416 417 static_assert(!has_visit<int>(0)); 418 static_assert(!has_visit<BadVariant>(0)); 419 static_assert(!has_visit<BadVariant2>(0)); 420 static_assert(has_visit<std::variant<int>>(0)); 421 static_assert(has_visit<GoodVariant>(0)); 422 static_assert(has_visit<GoodVariant2>(0)); 423 } 424 425 int main(int, char**) { 426 test_call_operator_forwarding(); 427 test_argument_forwarding(); 428 test_return_type(); 429 test_constexpr(); 430 test_exceptions(); 431 test_caller_accepts_nonconst(); 432 test_derived_from_variant(); 433 test_sfinae(); 434 435 return 0; 436 } 437