Loading libcxx/docs/Cxx2aStatusPaperStatus.csv +1 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ "`P0595R2 <https://wg21.link/P0595R2>`__","CWG","P0595R2 std::is_constant_evaluated()","San Diego","|Complete|","9.0" "`P0602R4 <https://wg21.link/P0602R4>`__","LWG","variant and optional should propagate copy/move triviality","San Diego","|Complete|","8.0" "`P0608R3 <https://wg21.link/P0608R3>`__","LWG","A sane variant converting constructor","San Diego","|Complete|","9.0" "`P0655R1 <https://wg21.link/P0655R1>`__","LWG","visit<R>: Explicit Return Type for visit","San Diego","* *","" "`P0655R1 <https://wg21.link/P0655R1>`__","LWG","visit<R>: Explicit Return Type for visit","San Diego","|Complete|","12.0" "`P0771R1 <https://wg21.link/P0771R1>`__","LWG","std::function move constructor should be noexcept","San Diego","|Complete|","6.0" "`P0896R4 <https://wg21.link/P0896R4>`__","LWG","The One Ranges Proposal","San Diego","* *","" "`P0899R1 <https://wg21.link/P0899R1>`__","LWG","P0899R1 - LWG 3016 is not a defect","San Diego","|Nothing To Do|","" Loading libcxx/include/variant +69 −6 Original line number Diff line number Diff line Loading @@ -169,6 +169,9 @@ namespace std { template <class Visitor, class... Variants> constexpr see below visit(Visitor&&, Variants&&...); template <class R, class Visitor, class... Variants> constexpr R visit(Visitor&&, Variants&&...); // since C++20 // 20.7.7, class monostate struct monostate; Loading Loading @@ -583,6 +586,16 @@ struct __variant { __make_value_visitor(_VSTD::forward<_Visitor>(__visitor)), _VSTD::forward<_Vs>(__vs)...); } #if _LIBCPP_STD_VER > 17 template <class _Rp, class _Visitor, class... _Vs> inline _LIBCPP_INLINE_VISIBILITY static constexpr _Rp __visit_value(_Visitor&& __visitor, _Vs&&... __vs) { return __visit_alt( __make_value_visitor<_Rp>(_VSTD::forward<_Visitor>(__visitor)), _VSTD::forward<_Vs>(__vs)...); } #endif private: template <class _Visitor, class... _Values> Loading @@ -605,12 +618,43 @@ private: _Visitor&& __visitor; }; #if _LIBCPP_STD_VER > 17 template <class _Rp, class _Visitor> struct __value_visitor_return_type { template <class... _Alts> inline _LIBCPP_INLINE_VISIBILITY constexpr _Rp operator()(_Alts&&... __alts) const { __std_visit_exhaustive_visitor_check< _Visitor, decltype((_VSTD::forward<_Alts>(__alts).__value))...>(); if constexpr (is_void_v<_Rp>) { _VSTD::__invoke_constexpr(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Alts>(__alts).__value...); } else { return _VSTD::__invoke_constexpr(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Alts>(__alts).__value...); } } _Visitor&& __visitor; }; #endif template <class _Visitor> inline _LIBCPP_INLINE_VISIBILITY static constexpr auto __make_value_visitor(_Visitor&& __visitor) { return __value_visitor<_Visitor>{_VSTD::forward<_Visitor>(__visitor)}; } #if _LIBCPP_STD_VER > 17 template <class _Rp, class _Visitor> inline _LIBCPP_INLINE_VISIBILITY static constexpr auto __make_value_visitor(_Visitor&& __visitor) { return __value_visitor_return_type<_Rp, _Visitor>{_VSTD::forward<_Visitor>(__visitor)}; } }; #endif } // namespace __visitation Loading Loading @@ -1594,18 +1638,37 @@ constexpr bool operator>=(const variant<_Types...>& __lhs, template <class _Visitor, class... _Vs> inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; bool __results[] = {__vs.valueless_by_exception()...}; for (bool __result : __results) { if (__result) { constexpr void __throw_if_valueless(_Visitor&& __visitor, _Vs&&... __vs) { const bool __valueless = (... || __vs.valueless_by_exception()); if (__valueless) { __throw_bad_variant_access(); } } template <class _Visitor, class... _Vs> inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; _VSTD::__throw_if_valueless(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); } #if _LIBCPP_STD_VER > 17 template <class _Rp, class _Visitor, class... _Vs> inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; _VSTD::__throw_if_valueless(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); return __variant::__visit_value<_Rp>(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); } #endif struct _LIBCPP_TEMPLATE_VIS monostate {}; inline _LIBCPP_INLINE_VISIBILITY Loading libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,10 @@ constexpr bool test(bool do_it) std::variant<Holder<Incomplete>*, int> v = nullptr; std::visit([](auto){}, v); std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v); #if TEST_STD_VER > 17 std::visit<void>([](auto){}, v); std::visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; }, v); #endif } return true; } Loading libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +0 −74 Original line number Diff line number Diff line Loading @@ -27,70 +27,8 @@ #include <variant> #include "test_macros.h" #include "type_id.h" #include "variant_test_helpers.h" enum CallType : unsigned { CT_None, CT_NonConst = 1, CT_Const = 2, CT_LValue = 4, CT_RValue = 8 }; inline constexpr CallType operator|(CallType LHS, CallType RHS) { return static_cast<CallType>(static_cast<unsigned>(LHS) | static_cast<unsigned>(RHS)); } struct ForwardingCallObject { template <class... Args> ForwardingCallObject& operator()(Args&&...) & { set_call<Args &&...>(CT_NonConst | CT_LValue); return *this; } template <class... Args> const ForwardingCallObject& operator()(Args&&...) const & { set_call<Args &&...>(CT_Const | CT_LValue); return *this; } template <class... Args> ForwardingCallObject&& operator()(Args&&...) && { set_call<Args &&...>(CT_NonConst | CT_RValue); return std::move(*this); } template <class... Args> const ForwardingCallObject&& operator()(Args&&...) const && { set_call<Args &&...>(CT_Const | CT_RValue); return std::move(*this); } template <class... Args> static void set_call(CallType type) { assert(last_call_type == CT_None); assert(last_call_args == nullptr); last_call_type = type; last_call_args = std::addressof(makeArgumentID<Args...>()); } template <class... Args> static bool check_call(CallType type) { bool result = last_call_type == type && last_call_args && *last_call_args == makeArgumentID<Args...>(); last_call_type = CT_None; last_call_args = nullptr; return result; } static CallType last_call_type; static const TypeID *last_call_args; }; CallType ForwardingCallObject::last_call_type = CT_None; const TypeID *ForwardingCallObject::last_call_args = nullptr; void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; Loading Loading @@ -296,18 +234,6 @@ void test_return_type() { } } struct ReturnFirst { template <class... Args> constexpr int operator()(int f, Args &&...) const { return f; } }; struct ReturnArity { template <class... Args> constexpr int operator()(Args &&...) const { return sizeof...(Args); } }; void test_constexpr() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; Loading libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp 0 → 100644 +430 −0 Original line number Diff line number Diff line // -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // Throwing bad_variant_access is supported starting in macosx10.13 // XFAIL: with_system_cxx_lib=macosx10.12 && !no-exceptions // XFAIL: with_system_cxx_lib=macosx10.11 && !no-exceptions // XFAIL: with_system_cxx_lib=macosx10.10 && !no-exceptions // XFAIL: with_system_cxx_lib=macosx10.9 && !no-exceptions // <variant> // template <class R, class Visitor, class... Variants> // constexpr R visit(Visitor&& vis, Variants&&... vars); #include <cassert> #include <memory> #include <string> #include <type_traits> #include <utility> #include <variant> #include "test_macros.h" #include "variant_test_helpers.h" template <typename ReturnType> void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; const Fn &cobj = obj; { // test call operator forwarding - no variant std::visit<ReturnType>(obj); assert(Fn::check_call<>(CT_NonConst | CT_LValue)); std::visit<ReturnType>(cobj); assert(Fn::check_call<>(CT_Const | CT_LValue)); std::visit<ReturnType>(std::move(obj)); assert(Fn::check_call<>(CT_NonConst | CT_RValue)); std::visit<ReturnType>(std::move(cobj)); assert(Fn::check_call<>(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, single arg using V = std::variant<int>; V v(42); std::visit<ReturnType>(obj, v); assert(Fn::check_call<int &>(CT_NonConst | CT_LValue)); std::visit<ReturnType>(cobj, v); assert(Fn::check_call<int &>(CT_Const | CT_LValue)); std::visit<ReturnType>(std::move(obj), v); assert(Fn::check_call<int &>(CT_NonConst | CT_RValue)); std::visit<ReturnType>(std::move(cobj), v); assert(Fn::check_call<int &>(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant<int, long, double>; V v(42l); std::visit<ReturnType>(obj, v); assert(Fn::check_call<long &>(CT_NonConst | CT_LValue)); std::visit<ReturnType>(cobj, v); assert(Fn::check_call<long &>(CT_Const | CT_LValue)); std::visit<ReturnType>(std::move(obj), v); assert(Fn::check_call<long &>(CT_NonConst | CT_RValue)); std::visit<ReturnType>(std::move(cobj), v); assert(Fn::check_call<long &>(CT_Const | CT_RValue)); } { // test call operator forwarding - multi variant, multi arg using V = std::variant<int, long, double>; using V2 = std::variant<int *, std::string>; V v(42l); V2 v2("hello"); std::visit<int>(obj, v, v2); assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue))); std::visit<ReturnType>(cobj, v, v2); assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue))); std::visit<ReturnType>(std::move(obj), v, v2); assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue))); std::visit<ReturnType>(std::move(cobj), v, v2); assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue))); } { using V = std::variant<int, long, double, std::string>; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit<ReturnType>(obj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue))); std::visit<ReturnType>(cobj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue))); std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue))); std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue))); } { using V = std::variant<int, long, double, int*, std::string>; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit<ReturnType>(obj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue))); std::visit<ReturnType>(cobj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue))); std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue))); std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue))); } } template <typename ReturnType> void test_argument_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; const auto Val = CT_LValue | CT_NonConst; { // single argument - value type using V = std::variant<int>; V v(42); const V &cv = v; std::visit<ReturnType>(obj, v); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, cv); assert(Fn::check_call<const int &>(Val)); std::visit<ReturnType>(obj, std::move(v)); assert(Fn::check_call<int &&>(Val)); std::visit<ReturnType>(obj, std::move(cv)); assert(Fn::check_call<const int &&>(Val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference using V = std::variant<int &>; int x = 42; V v(x); const V &cv = v; std::visit<ReturnType>(obj, v); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, cv); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, std::move(v)); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, std::move(cv)); assert(Fn::check_call<int &>(Val)); } { // single argument - rvalue reference using V = std::variant<int &&>; int x = 42; V v(std::move(x)); const V &cv = v; std::visit<ReturnType>(obj, v); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, cv); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, std::move(v)); assert(Fn::check_call<int &&>(Val)); std::visit<ReturnType>(obj, std::move(cv)); assert(Fn::check_call<int &&>(Val)); } #endif { // multi argument - multi variant using V = std::variant<int, std::string, long>; V v1(42), v2("hello"), v3(43l); std::visit<ReturnType>(obj, v1, v2, v3); assert((Fn::check_call<int &, std::string &, long &>(Val))); std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); assert((Fn::check_call<const int &, const std::string &, long &&>(Val))); } { using V = std::variant<int, long, double, std::string>; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit<ReturnType>(obj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(Val))); std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val))); } { using V = std::variant<int, long, double, int*, std::string>; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit<ReturnType>(obj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(Val))); std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val))); } } template <typename ReturnType> void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; const Fn &cobj = obj; { // test call operator forwarding - no variant static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj))), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj))), ReturnType>); } { // test call operator forwarding - single variant, single arg using V = std::variant<int>; V v(42); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - single variant, multi arg using V = std::variant<int, long, double>; V v(42l); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - multi variant, multi arg using V = std::variant<int, long, double>; using V2 = std::variant<int *, std::string>; V v(42l); V2 v2("hello"); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v, v2)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v, v2)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v, v2)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v, v2)), ReturnType>); } { using V = std::variant<int, long, double, std::string>; V v1(42l), v2("hello"), v3(101), v4(1.1); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4)), ReturnType>); } { using V = std::variant<int, long, double, int*, std::string>; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4)), ReturnType>); } } void test_constexpr_void() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; { using V = std::variant<int>; constexpr V v(42); static_assert((std::visit<void>(obj, v), 42) == 42, ""); } { using V = std::variant<short, long, char>; constexpr V v(42l); static_assert((std::visit<void>(obj, v), 42) == 42, ""); } { using V1 = std::variant<int>; using V2 = std::variant<int, char *, long long>; using V3 = std::variant<bool, int, int>; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); } { using V1 = std::variant<int>; using V2 = std::variant<int, char *, long long>; using V3 = std::variant<void *, int, int>; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); } { using V = std::variant<int, long, double, int *>; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); } { using V = std::variant<int, long, double, long long, int *>; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); } } void test_constexpr_int() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; { using V = std::variant<int>; constexpr V v(42); static_assert(std::visit<int>(obj, v) == 42, ""); } { using V = std::variant<short, long, char>; constexpr V v(42l); static_assert(std::visit<int>(obj, v) == 42, ""); } { using V1 = std::variant<int>; using V2 = std::variant<int, char *, long long>; using V3 = std::variant<bool, int, int>; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); } { using V1 = std::variant<int>; using V2 = std::variant<int, char *, long long>; using V3 = std::variant<void *, int, int>; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); } { using V = std::variant<int, long, double, int *>; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); } { using V = std::variant<int, long, double, long long, int *>; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); } } template <typename ReturnType> void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; auto test = [&](auto &&... args) { try { std::visit<ReturnType>(obj, args...); } catch (const std::bad_variant_access &) { return true; } catch (...) { } return false; }; { using V = std::variant<int, MakeEmptyT>; V v; makeEmpty(v); assert(test(v)); } { using V = std::variant<int, MakeEmptyT>; using V2 = std::variant<long, std::string, void *>; V v; makeEmpty(v); V2 v2("hello"); assert(test(v, v2)); } { using V = std::variant<int, MakeEmptyT>; using V2 = std::variant<long, std::string, void *>; V v; makeEmpty(v); V2 v2("hello"); assert(test(v2, v)); } { using V = std::variant<int, MakeEmptyT>; using V2 = std::variant<long, std::string, void *, MakeEmptyT>; V v; makeEmpty(v); V2 v2; makeEmpty(v2); assert(test(v, v2)); } { using V = std::variant<int, long, double, MakeEmptyT>; V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); assert(test(v1, v2, v3, v4)); } { using V = std::variant<int, long, double, long long, MakeEmptyT>; V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); makeEmpty(v2); makeEmpty(v3); makeEmpty(v4); assert(test(v1, v2, v3, v4)); } #endif } // See https://bugs.llvm.org/show_bug.cgi?id=31916 template <typename ReturnType> void test_caller_accepts_nonconst() { struct A {}; struct Visitor { auto operator()(A&) { if constexpr (!std::is_void_v<ReturnType>) { return ReturnType{}; } } }; std::variant<A> v; std::visit<ReturnType>(Visitor{}, v); } void test_constexpr_explicit_side_effect() { auto test_lambda = [](int arg) constexpr { std::variant<int> v = 101; std::visit<void>([arg](int& x) constexpr { x = arg; }, v); return std::get<int>(v); }; static_assert(test_lambda(202) == 202, ""); } int main(int, char**) { test_call_operator_forwarding<void>(); test_argument_forwarding<void>(); test_return_type<void>(); test_constexpr_void(); test_exceptions<void>(); test_caller_accepts_nonconst<void>(); test_call_operator_forwarding<int>(); test_argument_forwarding<int>(); test_return_type<int>(); test_constexpr_int(); test_exceptions<int>(); test_caller_accepts_nonconst<int>(); test_constexpr_explicit_side_effect(); return 0; } Loading
libcxx/docs/Cxx2aStatusPaperStatus.csv +1 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ "`P0595R2 <https://wg21.link/P0595R2>`__","CWG","P0595R2 std::is_constant_evaluated()","San Diego","|Complete|","9.0" "`P0602R4 <https://wg21.link/P0602R4>`__","LWG","variant and optional should propagate copy/move triviality","San Diego","|Complete|","8.0" "`P0608R3 <https://wg21.link/P0608R3>`__","LWG","A sane variant converting constructor","San Diego","|Complete|","9.0" "`P0655R1 <https://wg21.link/P0655R1>`__","LWG","visit<R>: Explicit Return Type for visit","San Diego","* *","" "`P0655R1 <https://wg21.link/P0655R1>`__","LWG","visit<R>: Explicit Return Type for visit","San Diego","|Complete|","12.0" "`P0771R1 <https://wg21.link/P0771R1>`__","LWG","std::function move constructor should be noexcept","San Diego","|Complete|","6.0" "`P0896R4 <https://wg21.link/P0896R4>`__","LWG","The One Ranges Proposal","San Diego","* *","" "`P0899R1 <https://wg21.link/P0899R1>`__","LWG","P0899R1 - LWG 3016 is not a defect","San Diego","|Nothing To Do|","" Loading
libcxx/include/variant +69 −6 Original line number Diff line number Diff line Loading @@ -169,6 +169,9 @@ namespace std { template <class Visitor, class... Variants> constexpr see below visit(Visitor&&, Variants&&...); template <class R, class Visitor, class... Variants> constexpr R visit(Visitor&&, Variants&&...); // since C++20 // 20.7.7, class monostate struct monostate; Loading Loading @@ -583,6 +586,16 @@ struct __variant { __make_value_visitor(_VSTD::forward<_Visitor>(__visitor)), _VSTD::forward<_Vs>(__vs)...); } #if _LIBCPP_STD_VER > 17 template <class _Rp, class _Visitor, class... _Vs> inline _LIBCPP_INLINE_VISIBILITY static constexpr _Rp __visit_value(_Visitor&& __visitor, _Vs&&... __vs) { return __visit_alt( __make_value_visitor<_Rp>(_VSTD::forward<_Visitor>(__visitor)), _VSTD::forward<_Vs>(__vs)...); } #endif private: template <class _Visitor, class... _Values> Loading @@ -605,12 +618,43 @@ private: _Visitor&& __visitor; }; #if _LIBCPP_STD_VER > 17 template <class _Rp, class _Visitor> struct __value_visitor_return_type { template <class... _Alts> inline _LIBCPP_INLINE_VISIBILITY constexpr _Rp operator()(_Alts&&... __alts) const { __std_visit_exhaustive_visitor_check< _Visitor, decltype((_VSTD::forward<_Alts>(__alts).__value))...>(); if constexpr (is_void_v<_Rp>) { _VSTD::__invoke_constexpr(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Alts>(__alts).__value...); } else { return _VSTD::__invoke_constexpr(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Alts>(__alts).__value...); } } _Visitor&& __visitor; }; #endif template <class _Visitor> inline _LIBCPP_INLINE_VISIBILITY static constexpr auto __make_value_visitor(_Visitor&& __visitor) { return __value_visitor<_Visitor>{_VSTD::forward<_Visitor>(__visitor)}; } #if _LIBCPP_STD_VER > 17 template <class _Rp, class _Visitor> inline _LIBCPP_INLINE_VISIBILITY static constexpr auto __make_value_visitor(_Visitor&& __visitor) { return __value_visitor_return_type<_Rp, _Visitor>{_VSTD::forward<_Visitor>(__visitor)}; } }; #endif } // namespace __visitation Loading Loading @@ -1594,18 +1638,37 @@ constexpr bool operator>=(const variant<_Types...>& __lhs, template <class _Visitor, class... _Vs> inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; bool __results[] = {__vs.valueless_by_exception()...}; for (bool __result : __results) { if (__result) { constexpr void __throw_if_valueless(_Visitor&& __visitor, _Vs&&... __vs) { const bool __valueless = (... || __vs.valueless_by_exception()); if (__valueless) { __throw_bad_variant_access(); } } template <class _Visitor, class... _Vs> inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; _VSTD::__throw_if_valueless(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); } #if _LIBCPP_STD_VER > 17 template <class _Rp, class _Visitor, class... _Vs> inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; _VSTD::__throw_if_valueless(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); return __variant::__visit_value<_Rp>(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); } #endif struct _LIBCPP_TEMPLATE_VIS monostate {}; inline _LIBCPP_INLINE_VISIBILITY Loading
libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,10 @@ constexpr bool test(bool do_it) std::variant<Holder<Incomplete>*, int> v = nullptr; std::visit([](auto){}, v); std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v); #if TEST_STD_VER > 17 std::visit<void>([](auto){}, v); std::visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; }, v); #endif } return true; } Loading
libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +0 −74 Original line number Diff line number Diff line Loading @@ -27,70 +27,8 @@ #include <variant> #include "test_macros.h" #include "type_id.h" #include "variant_test_helpers.h" enum CallType : unsigned { CT_None, CT_NonConst = 1, CT_Const = 2, CT_LValue = 4, CT_RValue = 8 }; inline constexpr CallType operator|(CallType LHS, CallType RHS) { return static_cast<CallType>(static_cast<unsigned>(LHS) | static_cast<unsigned>(RHS)); } struct ForwardingCallObject { template <class... Args> ForwardingCallObject& operator()(Args&&...) & { set_call<Args &&...>(CT_NonConst | CT_LValue); return *this; } template <class... Args> const ForwardingCallObject& operator()(Args&&...) const & { set_call<Args &&...>(CT_Const | CT_LValue); return *this; } template <class... Args> ForwardingCallObject&& operator()(Args&&...) && { set_call<Args &&...>(CT_NonConst | CT_RValue); return std::move(*this); } template <class... Args> const ForwardingCallObject&& operator()(Args&&...) const && { set_call<Args &&...>(CT_Const | CT_RValue); return std::move(*this); } template <class... Args> static void set_call(CallType type) { assert(last_call_type == CT_None); assert(last_call_args == nullptr); last_call_type = type; last_call_args = std::addressof(makeArgumentID<Args...>()); } template <class... Args> static bool check_call(CallType type) { bool result = last_call_type == type && last_call_args && *last_call_args == makeArgumentID<Args...>(); last_call_type = CT_None; last_call_args = nullptr; return result; } static CallType last_call_type; static const TypeID *last_call_args; }; CallType ForwardingCallObject::last_call_type = CT_None; const TypeID *ForwardingCallObject::last_call_args = nullptr; void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; Loading Loading @@ -296,18 +234,6 @@ void test_return_type() { } } struct ReturnFirst { template <class... Args> constexpr int operator()(int f, Args &&...) const { return f; } }; struct ReturnArity { template <class... Args> constexpr int operator()(Args &&...) const { return sizeof...(Args); } }; void test_constexpr() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; Loading
libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp 0 → 100644 +430 −0 Original line number Diff line number Diff line // -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // Throwing bad_variant_access is supported starting in macosx10.13 // XFAIL: with_system_cxx_lib=macosx10.12 && !no-exceptions // XFAIL: with_system_cxx_lib=macosx10.11 && !no-exceptions // XFAIL: with_system_cxx_lib=macosx10.10 && !no-exceptions // XFAIL: with_system_cxx_lib=macosx10.9 && !no-exceptions // <variant> // template <class R, class Visitor, class... Variants> // constexpr R visit(Visitor&& vis, Variants&&... vars); #include <cassert> #include <memory> #include <string> #include <type_traits> #include <utility> #include <variant> #include "test_macros.h" #include "variant_test_helpers.h" template <typename ReturnType> void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; const Fn &cobj = obj; { // test call operator forwarding - no variant std::visit<ReturnType>(obj); assert(Fn::check_call<>(CT_NonConst | CT_LValue)); std::visit<ReturnType>(cobj); assert(Fn::check_call<>(CT_Const | CT_LValue)); std::visit<ReturnType>(std::move(obj)); assert(Fn::check_call<>(CT_NonConst | CT_RValue)); std::visit<ReturnType>(std::move(cobj)); assert(Fn::check_call<>(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, single arg using V = std::variant<int>; V v(42); std::visit<ReturnType>(obj, v); assert(Fn::check_call<int &>(CT_NonConst | CT_LValue)); std::visit<ReturnType>(cobj, v); assert(Fn::check_call<int &>(CT_Const | CT_LValue)); std::visit<ReturnType>(std::move(obj), v); assert(Fn::check_call<int &>(CT_NonConst | CT_RValue)); std::visit<ReturnType>(std::move(cobj), v); assert(Fn::check_call<int &>(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant<int, long, double>; V v(42l); std::visit<ReturnType>(obj, v); assert(Fn::check_call<long &>(CT_NonConst | CT_LValue)); std::visit<ReturnType>(cobj, v); assert(Fn::check_call<long &>(CT_Const | CT_LValue)); std::visit<ReturnType>(std::move(obj), v); assert(Fn::check_call<long &>(CT_NonConst | CT_RValue)); std::visit<ReturnType>(std::move(cobj), v); assert(Fn::check_call<long &>(CT_Const | CT_RValue)); } { // test call operator forwarding - multi variant, multi arg using V = std::variant<int, long, double>; using V2 = std::variant<int *, std::string>; V v(42l); V2 v2("hello"); std::visit<int>(obj, v, v2); assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue))); std::visit<ReturnType>(cobj, v, v2); assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue))); std::visit<ReturnType>(std::move(obj), v, v2); assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue))); std::visit<ReturnType>(std::move(cobj), v, v2); assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue))); } { using V = std::variant<int, long, double, std::string>; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit<ReturnType>(obj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue))); std::visit<ReturnType>(cobj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue))); std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue))); std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue))); } { using V = std::variant<int, long, double, int*, std::string>; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit<ReturnType>(obj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue))); std::visit<ReturnType>(cobj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue))); std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue))); std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue))); } } template <typename ReturnType> void test_argument_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; const auto Val = CT_LValue | CT_NonConst; { // single argument - value type using V = std::variant<int>; V v(42); const V &cv = v; std::visit<ReturnType>(obj, v); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, cv); assert(Fn::check_call<const int &>(Val)); std::visit<ReturnType>(obj, std::move(v)); assert(Fn::check_call<int &&>(Val)); std::visit<ReturnType>(obj, std::move(cv)); assert(Fn::check_call<const int &&>(Val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference using V = std::variant<int &>; int x = 42; V v(x); const V &cv = v; std::visit<ReturnType>(obj, v); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, cv); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, std::move(v)); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, std::move(cv)); assert(Fn::check_call<int &>(Val)); } { // single argument - rvalue reference using V = std::variant<int &&>; int x = 42; V v(std::move(x)); const V &cv = v; std::visit<ReturnType>(obj, v); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, cv); assert(Fn::check_call<int &>(Val)); std::visit<ReturnType>(obj, std::move(v)); assert(Fn::check_call<int &&>(Val)); std::visit<ReturnType>(obj, std::move(cv)); assert(Fn::check_call<int &&>(Val)); } #endif { // multi argument - multi variant using V = std::variant<int, std::string, long>; V v1(42), v2("hello"), v3(43l); std::visit<ReturnType>(obj, v1, v2, v3); assert((Fn::check_call<int &, std::string &, long &>(Val))); std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); assert((Fn::check_call<const int &, const std::string &, long &&>(Val))); } { using V = std::variant<int, long, double, std::string>; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit<ReturnType>(obj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int &, double &>(Val))); std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val))); } { using V = std::variant<int, long, double, int*, std::string>; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit<ReturnType>(obj, v1, v2, v3, v4); assert((Fn::check_call<long &, std::string &, int *&, double &>(Val))); std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val))); } } template <typename ReturnType> void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; const Fn &cobj = obj; { // test call operator forwarding - no variant static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj))), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj))), ReturnType>); } { // test call operator forwarding - single variant, single arg using V = std::variant<int>; V v(42); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - single variant, multi arg using V = std::variant<int, long, double>; V v(42l); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - multi variant, multi arg using V = std::variant<int, long, double>; using V2 = std::variant<int *, std::string>; V v(42l); V2 v2("hello"); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v, v2)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v, v2)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v, v2)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v, v2)), ReturnType>); } { using V = std::variant<int, long, double, std::string>; V v1(42l), v2("hello"), v3(101), v4(1.1); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4)), ReturnType>); } { using V = std::variant<int, long, double, int*, std::string>; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4)), ReturnType>); } } void test_constexpr_void() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; { using V = std::variant<int>; constexpr V v(42); static_assert((std::visit<void>(obj, v), 42) == 42, ""); } { using V = std::variant<short, long, char>; constexpr V v(42l); static_assert((std::visit<void>(obj, v), 42) == 42, ""); } { using V1 = std::variant<int>; using V2 = std::variant<int, char *, long long>; using V3 = std::variant<bool, int, int>; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); } { using V1 = std::variant<int>; using V2 = std::variant<int, char *, long long>; using V3 = std::variant<void *, int, int>; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); } { using V = std::variant<int, long, double, int *>; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); } { using V = std::variant<int, long, double, long long, int *>; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); } } void test_constexpr_int() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; { using V = std::variant<int>; constexpr V v(42); static_assert(std::visit<int>(obj, v) == 42, ""); } { using V = std::variant<short, long, char>; constexpr V v(42l); static_assert(std::visit<int>(obj, v) == 42, ""); } { using V1 = std::variant<int>; using V2 = std::variant<int, char *, long long>; using V3 = std::variant<bool, int, int>; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); } { using V1 = std::variant<int>; using V2 = std::variant<int, char *, long long>; using V3 = std::variant<void *, int, int>; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); } { using V = std::variant<int, long, double, int *>; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); } { using V = std::variant<int, long, double, long long, int *>; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); } } template <typename ReturnType> void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; auto test = [&](auto &&... args) { try { std::visit<ReturnType>(obj, args...); } catch (const std::bad_variant_access &) { return true; } catch (...) { } return false; }; { using V = std::variant<int, MakeEmptyT>; V v; makeEmpty(v); assert(test(v)); } { using V = std::variant<int, MakeEmptyT>; using V2 = std::variant<long, std::string, void *>; V v; makeEmpty(v); V2 v2("hello"); assert(test(v, v2)); } { using V = std::variant<int, MakeEmptyT>; using V2 = std::variant<long, std::string, void *>; V v; makeEmpty(v); V2 v2("hello"); assert(test(v2, v)); } { using V = std::variant<int, MakeEmptyT>; using V2 = std::variant<long, std::string, void *, MakeEmptyT>; V v; makeEmpty(v); V2 v2; makeEmpty(v2); assert(test(v, v2)); } { using V = std::variant<int, long, double, MakeEmptyT>; V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); assert(test(v1, v2, v3, v4)); } { using V = std::variant<int, long, double, long long, MakeEmptyT>; V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); makeEmpty(v2); makeEmpty(v3); makeEmpty(v4); assert(test(v1, v2, v3, v4)); } #endif } // See https://bugs.llvm.org/show_bug.cgi?id=31916 template <typename ReturnType> void test_caller_accepts_nonconst() { struct A {}; struct Visitor { auto operator()(A&) { if constexpr (!std::is_void_v<ReturnType>) { return ReturnType{}; } } }; std::variant<A> v; std::visit<ReturnType>(Visitor{}, v); } void test_constexpr_explicit_side_effect() { auto test_lambda = [](int arg) constexpr { std::variant<int> v = 101; std::visit<void>([arg](int& x) constexpr { x = arg; }, v); return std::get<int>(v); }; static_assert(test_lambda(202) == 202, ""); } int main(int, char**) { test_call_operator_forwarding<void>(); test_argument_forwarding<void>(); test_return_type<void>(); test_constexpr_void(); test_exceptions<void>(); test_caller_accepts_nonconst<void>(); test_call_operator_forwarding<int>(); test_argument_forwarding<int>(); test_return_type<int>(); test_constexpr_int(); test_exceptions<int>(); test_caller_accepts_nonconst<int>(); test_constexpr_explicit_side_effect(); return 0; }