[libc] [libcxx] [flang] [compiler-rt] [clang-tools-extra] [llvm] [lld] [clang] [lldb] [libc++][variant] P2637R3: Member `visit` (`std::variant`) (PR #76447)
Hristo Hristov via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 18 07:00:22 PST 2024
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/76447
>From f8c52dc689243062ca7627c3b6ca04bea69e67e9 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 18 Dec 2023 14:46:15 +0200
Subject: [PATCH 01/28] [libc++][variant] P2637R3 - Member visit
---
libcxx/include/variant | 22 +++++++++++++++++++
.../variant/variant.visit/visit.pass.cpp | 3 +++
2 files changed, 25 insertions(+)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 3b01e5e126d9fa..c5810c218a43a7 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -69,6 +69,12 @@ namespace std {
// 20.7.2.6, swap
void swap(variant&) noexcept(see below);
+
+ // [variant.visit], visitation
+ template<class Self, class Visitor>
+ constexpr decltype(auto) visit(this Self&&, Visitor&&);
+ template<class R, class Self, class Visitor>
+ constexpr R visit(this Self&&, Visitor&&);
};
// 20.7.3, variant helper classes
@@ -235,6 +241,7 @@ namespace std {
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
#include <__utility/forward.h>
+#include <__utility/forward_like.h>
#include <__utility/in_place.h>
#include <__utility/move.h>
#include <__utility/swap.h>
@@ -1490,6 +1497,21 @@ public:
__impl_.__swap(__that.__impl_);
}
+# if _LIBCPP_STD_VER >= 26
+ // [variant.visit], visitation
+ template <class _Self, class _Visitor>
+ constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
+ using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+ return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
+ }
+
+ template <class _R, class _Self, class _Visitor>
+ constexpr _R visit(this _Self&& __self, _Visitor&& __visitor) {
+ using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+ return std::visit<_R>(std::forward<_Visitor>(__visitor), (_V)__self);
+ }
+# endif
+
private:
__variant_detail::__impl<_Types...> __impl_;
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 097b784f2bf2ce..0dcda177ba3f8f 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -47,6 +47,9 @@ void test_call_operator_forwarding() {
assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
std::visit(std::move(cobj), v);
assert(Fn::check_call<int &>(CT_Const | CT_RValue));
+
+ v.visit(obj);
+ assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
>From 68075dde56db65d8bbde8660cafe8008eba17f46 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 24 Dec 2023 09:35:42 +0200
Subject: [PATCH 02/28] WIP: Test via macro
---
libcxx/include/variant | 28 ++-
.../variant/variant.visit/visit.pass.cpp | 197 +++++++++++-------
2 files changed, 145 insertions(+), 80 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index a4f8371ba6acdf..0da61901ce35ff 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1283,16 +1283,10 @@ public:
# if _LIBCPP_STD_VER >= 26
// [variant.visit], visitation
template <class _Self, class _Visitor>
- constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
- using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
- return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
- }
+ constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);
template <class _R, class _Self, class _Visitor>
- constexpr _R visit(this _Self&& __self, _Visitor&& __visitor) {
- using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
- return std::visit<_R>(std::forward<_Visitor>(__visitor), (_V)__self);
- }
+ constexpr _R visit(this _Self&& __self, _Visitor&& __visitor);
# endif
private:
@@ -1554,6 +1548,24 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) {
}
# endif
+# if _LIBCPP_STD_VER >= 26
+// [variant.visit], visitation
+
+template <class... _Types>
+template <class _Self, class _Visitor>
+constexpr decltype(auto) variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) {
+ using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+ return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
+}
+
+template <class... _Types>
+template <class _Rp, class _Self, class _Visitor>
+constexpr _Rp variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) {
+ using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+ return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self);
+}
+# endif
+
template <class... _Types>
_LIBCPP_HIDE_FROM_ABI auto
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs)))
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 0dcda177ba3f8f..b46924683af66e 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -22,10 +22,22 @@
#include "test_macros.h"
#include "variant_test_helpers.h"
+#if _LIBCPP_STD_VER >= 26
+# define TEST_VISIT(object, variants, expectedValue, type, ...) \
+ std::visit(object, variants); \
+ assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue)); \
+ variants.visit(object); \
+ assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue));
+#else
+# define TEST_VISIT(object, variants, expectedValue, type, ...) \
+ std::visit(object, variants); \
+ assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue));
+#endif
+
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn &cobj = obj;
+ const Fn& cobj = obj;
{ // test call operator forwarding - no variant
std::visit(obj);
assert(Fn::check_call<>(CT_NonConst | CT_LValue));
@@ -39,67 +51,108 @@ void test_call_operator_forwarding() {
{ // test call operator forwarding - single variant, single arg
using V = std::variant<int>;
V v(42);
+
+ // non-member
std::visit(obj, v);
- assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
std::visit(cobj, v);
- assert(Fn::check_call<int &>(CT_Const | CT_LValue));
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
std::visit(std::move(obj), v);
- assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
std::visit(std::move(cobj), v);
- assert(Fn::check_call<int &>(CT_Const | CT_RValue));
+ assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+ // member
+#if _LIBCPP_STD_VER >= 26
v.visit(obj);
- assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ v.visit(cobj);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ v.visit(std::move(obj));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ v.visit(std::move(cobj));
+ assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+#endif
+
+#define TEST_VISIT1(type, object, variants, expectedValue) \
+ std::visit(object, variants); \
+ assert(Fn::check_call<type&>(expectedValue)); \
+ variants.visit(object); \
+ assert(Fn::check_call<type&>(expectedValue));
+
+ TEST_VISIT1(int, obj, v, (CT_NonConst | CT_LValue));
+ TEST_VISIT1(int, cobj, v, (CT_Const | CT_LValue));
+ TEST_VISIT1(int, std::move(obj), v, (CT_NonConst | CT_RValue));
+ TEST_VISIT1(int, std::move(cobj), v, (CT_Const | CT_RValue));
+
+ TEST_VISIT(obj, v, (CT_NonConst | CT_LValue), int&);
+ TEST_VISIT(cobj, v, (CT_Const | CT_LValue), int&);
+ TEST_VISIT(std::move(obj), v, (CT_NonConst | CT_RValue), int&);
+ TEST_VISIT(std::move(cobj), v, (CT_Const | CT_RValue), int&);
+
+ // TEST_VISIT2(td::move(cobj), v, (CT_Const | CT_RValue), int&, long&, float&);
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
V v(42l);
std::visit(obj, v);
- assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
std::visit(cobj, v);
- assert(Fn::check_call<long &>(CT_Const | CT_LValue));
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
std::visit(std::move(obj), v);
- assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
std::visit(std::move(cobj), v);
- assert(Fn::check_call<long &>(CT_Const | CT_RValue));
+ assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+
+ TEST_VISIT(obj, v, (CT_NonConst | CT_LValue), long&);
+ TEST_VISIT(cobj, v, (CT_Const | CT_LValue), long&);
+ TEST_VISIT(std::move(obj), v, (CT_NonConst | CT_RValue), long&);
+ TEST_VISIT(std::move(cobj), v, (CT_Const | CT_RValue), long&);
}
{ // test call operator forwarding - multi variant, multi arg
- using V = std::variant<int, long, double>;
- using V2 = std::variant<int *, std::string>;
+ using V = std::variant<int, long, double>;
+ using V2 = std::variant<int*, std::string>;
V v(42l);
V2 v2("hello");
std::visit(obj, v, v2);
- assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
+ assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
std::visit(cobj, v, v2);
- assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
+ assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
std::visit(std::move(obj), v, v2);
- assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
+ assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
std::visit(std::move(cobj), v, v2);
- assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
+ assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
+
+ TEST_VISIT(obj, v, v2, CT_NonConst | CT_LValue)));
+ TEST_VISIT(cobj, v, v2, (CT_Const | CT_LValue)));
+ TEST_VISIT(std::move(obj), v, v2);
+ assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
+ TEST_VISIT(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(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue)));
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
std::visit(cobj, v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue)));
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
std::visit(std::move(obj), v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue)));
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
std::visit(std::move(cobj), v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue)));
+ 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(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue)));
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
std::visit(cobj, v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue)));
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
std::visit(std::move(obj), v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue)));
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
std::visit(std::move(cobj), v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
}
}
@@ -110,76 +163,76 @@ void test_argument_forwarding() {
{ // single argument - value type
using V = std::variant<int>;
V v(42);
- const V &cv = v;
+ const V& cv = v;
std::visit(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit(obj, cv);
- assert(Fn::check_call<const int &>(Val));
+ assert(Fn::check_call<const int&>(Val));
std::visit(obj, std::move(v));
- assert(Fn::check_call<int &&>(Val));
+ assert(Fn::check_call<int&&>(Val));
std::visit(obj, std::move(cv));
- assert(Fn::check_call<const int &&>(Val));
+ 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;
+ using V = std::variant<int&>;
+ int x = 42;
V v(x);
- const V &cv = v;
+ const V& cv = v;
std::visit(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit(obj, cv);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit(obj, std::move(v));
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit(obj, std::move(cv));
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
}
{ // single argument - rvalue reference
- using V = std::variant<int &&>;
- int x = 42;
+ using V = std::variant<int&&>;
+ int x = 42;
V v(std::move(x));
- const V &cv = v;
+ const V& cv = v;
std::visit(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit(obj, cv);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit(obj, std::move(v));
- assert(Fn::check_call<int &&>(Val));
+ assert(Fn::check_call<int&&>(Val));
std::visit(obj, std::move(cv));
- assert(Fn::check_call<int &&>(Val));
+ 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(obj, v1, v2, v3);
- assert((Fn::check_call<int &, std::string &, long &>(Val)));
+ assert((Fn::check_call<int&, std::string&, long&>(Val)));
std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
- assert((Fn::check_call<const int &, const std::string &, long &&>(Val)));
+ 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(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int &, double &>(Val)));
+ assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
std::visit(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)));
+ 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(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long &, std::string &, int *&, double &>(Val)));
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
std::visit(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)));
+ assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(Val)));
}
}
void test_return_type() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn &cobj = obj;
+ const Fn& cobj = obj;
{ // test call operator forwarding - no variant
static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
@@ -203,8 +256,8 @@ void test_return_type() {
static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
}
{ // test call operator forwarding - multi variant, multi arg
- using V = std::variant<int, long, double>;
- using V2 = std::variant<int *, std::string>;
+ 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(obj, v, v2)), Fn&>);
@@ -245,7 +298,7 @@ void test_constexpr() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
+ using V2 = std::variant<int, char*, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
@@ -254,20 +307,20 @@ void test_constexpr() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
- using V3 = std::variant<void *, int, 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(aobj, v1, v2, v3) == 3, "");
}
{
- using V = std::variant<int, long, double, int *>;
+ using V = std::variant<int, long, double, int*>;
constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");
}
{
- using V = std::variant<int, long, double, long long, int *>;
+ 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(aobj, v1, v2, v3, v4) == 4, "");
}
@@ -276,10 +329,10 @@ void test_constexpr() {
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
- auto test = [&](auto &&... args) {
+ auto test = [&](auto&&... args) {
try {
std::visit(obj, args...);
- } catch (const std::bad_variant_access &) {
+ } catch (const std::bad_variant_access&) {
return true;
} catch (...) {
}
@@ -292,24 +345,24 @@ void test_exceptions() {
assert(test(v));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void *>;
+ 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 *>;
+ 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>;
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void*, MakeEmptyT>;
V v;
makeEmpty(v);
V2 v2;
@@ -354,7 +407,7 @@ void get(const MyVariant&) {
} // namespace std
void test_derived_from_variant() {
- auto v1 = MyVariant{42};
+ auto v1 = MyVariant{42};
const auto cv1 = MyVariant{142};
std::visit([](auto x) { assert(x == 42); }, v1);
std::visit([](auto x) { assert(x == 142); }, cv1);
@@ -368,9 +421,7 @@ void test_derived_from_variant() {
char valueless_by_exception;
};
- struct EvilVariant1 : std::variant<int, long, double>,
- std::tuple<int>,
- EvilVariantBase {
+ struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
using std::variant<int, long, double>::variant;
};
@@ -380,7 +431,10 @@ void test_derived_from_variant() {
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
struct Callable {
- bool operator()() const { assert(false); return false; }
+ bool operator()() const {
+ assert(false);
+ return false;
+ }
};
Callable __impl;
@@ -399,8 +453,7 @@ struct any_visitor {
void operator()(const T&) const {}
};
-template <typename T, typename = decltype(std::visit(
- std::declval<any_visitor&>(), std::declval<T>()))>
+template <typename T, typename = decltype(std::visit(std::declval<any_visitor&>(), std::declval<T>()))>
constexpr bool has_visit(int) {
return true;
}
>From 0bc0832e848bd01c40337dab9344aa506501a792 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 24 Dec 2023 09:43:27 +0200
Subject: [PATCH 03/28] WIP: visit.pass
---
.../variant/variant.visit/visit.pass.cpp | 115 +++++++-----------
1 file changed, 47 insertions(+), 68 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index b46924683af66e..3fac6b21f2682a 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -22,18 +22,6 @@
#include "test_macros.h"
#include "variant_test_helpers.h"
-#if _LIBCPP_STD_VER >= 26
-# define TEST_VISIT(object, variants, expectedValue, type, ...) \
- std::visit(object, variants); \
- assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue)); \
- variants.visit(object); \
- assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue));
-#else
-# define TEST_VISIT(object, variants, expectedValue, type, ...) \
- std::visit(object, variants); \
- assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue));
-#endif
-
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
@@ -51,63 +39,61 @@ void test_call_operator_forwarding() {
{ // test call operator forwarding - single variant, single arg
using V = std::variant<int>;
V v(42);
-
- // non-member
- std::visit(obj, v);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
- std::visit(cobj, v);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
- std::visit(std::move(obj), v);
- assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
- std::visit(std::move(cobj), v);
- assert(Fn::check_call<int&>(CT_Const | CT_RValue));
-
- // member
#if _LIBCPP_STD_VER >= 26
- v.visit(obj);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
- v.visit(cobj);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
- v.visit(std::move(obj));
- assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
- v.visit(std::move(cobj));
- assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ v.visit(cobj);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ v.visit(std::move(obj));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ v.visit(std::move(cobj));
+ assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+ }
#endif
-#define TEST_VISIT1(type, object, variants, expectedValue) \
- std::visit(object, variants); \
- assert(Fn::check_call<type&>(expectedValue)); \
- variants.visit(object); \
- assert(Fn::check_call<type&>(expectedValue));
-
- TEST_VISIT1(int, obj, v, (CT_NonConst | CT_LValue));
- TEST_VISIT1(int, cobj, v, (CT_Const | CT_LValue));
- TEST_VISIT1(int, std::move(obj), v, (CT_NonConst | CT_RValue));
- TEST_VISIT1(int, std::move(cobj), v, (CT_Const | CT_RValue));
-
- TEST_VISIT(obj, v, (CT_NonConst | CT_LValue), int&);
- TEST_VISIT(cobj, v, (CT_Const | CT_LValue), int&);
- TEST_VISIT(std::move(obj), v, (CT_NonConst | CT_RValue), int&);
- TEST_VISIT(std::move(cobj), v, (CT_Const | CT_RValue), int&);
-
- // TEST_VISIT2(td::move(cobj), v, (CT_Const | CT_RValue), int&, long&, float&);
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ std::visit(cobj, v);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ std::visit(std::move(obj), v);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ std::visit(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(obj, v);
- assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
- std::visit(cobj, v);
- assert(Fn::check_call<long&>(CT_Const | CT_LValue));
- std::visit(std::move(obj), v);
- assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
- std::visit(std::move(cobj), v);
- assert(Fn::check_call<long&>(CT_Const | CT_RValue));
- TEST_VISIT(obj, v, (CT_NonConst | CT_LValue), long&);
- TEST_VISIT(cobj, v, (CT_Const | CT_LValue), long&);
- TEST_VISIT(std::move(obj), v, (CT_NonConst | CT_RValue), long&);
- TEST_VISIT(std::move(cobj), v, (CT_Const | CT_RValue), long&);
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+ v.visit(cobj);
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ v.visit(std::move(obj));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+ v.visit(std::move(cobj));
+ assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+ }
+#endif
+
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+ std::visit(cobj, v);
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ std::visit(std::move(obj), v);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+ std::visit(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>;
@@ -122,13 +108,6 @@ void test_call_operator_forwarding() {
assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
std::visit(std::move(cobj), v, v2);
assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
-
- TEST_VISIT(obj, v, v2, CT_NonConst | CT_LValue)));
- TEST_VISIT(cobj, v, v2, (CT_Const | CT_LValue)));
- TEST_VISIT(std::move(obj), v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
- TEST_VISIT(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>;
>From 1de898e6d27795b159526055b400e68faa7aff11 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 24 Dec 2023 10:09:54 +0200
Subject: [PATCH 04/28] template_argument
---
libcxx/docs/Status/Cxx2c.rst | 2 +
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
.../variant.visit/robust_against_adl.pass.cpp | 54 ++--
.../variant/variant.visit/visit.pass.cpp | 264 ++++++++++++------
.../variant.visit/visit_return_type.pass.cpp | 206 ++++++++------
.../generate_feature_test_macro_components.py | 6 +-
6 files changed, 348 insertions(+), 186 deletions(-)
diff --git a/libcxx/docs/Status/Cxx2c.rst b/libcxx/docs/Status/Cxx2c.rst
index a7ebc4662f517c..5c700d2cb0d6d3 100644
--- a/libcxx/docs/Status/Cxx2c.rst
+++ b/libcxx/docs/Status/Cxx2c.rst
@@ -40,6 +40,8 @@ Paper Status
.. note::
.. [#note-P2510R3] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
+ .. [#note-P2637R3] P2637R3: Implemented `variant` member `visit`
+
.. _issues-status-cxx2c:
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index ff83648aa76830..a3214ab2bfe75c 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -17,7 +17,7 @@
"`P0792R14 <https://wg21.link/P0792R14>`__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","",""
"`P2874R2 <https://wg21.link/P2874R2>`__","LWG","Mandating Annex D Require No More","Varna June 2023","","",""
"`P2757R3 <https://wg21.link/P2757R3>`__","LWG","Type-checking format args","Varna June 2023","","","|format|"
-"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","","","|format|"
+"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","|Partial| [#note-P2637R3]","18.0",""
"`P2641R4 <https://wg21.link/P2641R4>`__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","",""
"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","","",""
"`P2697R1 <https://wg21.link/P2697R1>`__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0",""
diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
index 6f17fa32648d41..6f095891693867 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
@@ -9,6 +9,13 @@
// UNSUPPORTED: c++03, c++11, c++14
// <variant>
+
+// class variant;
+// template<class Self, class Visitor>
+// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
+// template<class R, class Self, class Visitor>
+// constexpr R visit(this Self&&, Visitor&&); // since C++26
+
// template <class Visitor, class... Variants>
// constexpr see below visit(Visitor&& vis, Variants&&... vars);
@@ -17,27 +24,42 @@
#include "test_macros.h"
struct Incomplete;
-template<class T> struct Holder { T t; };
-
-constexpr bool test(bool do_it)
-{
- if (do_it) {
- std::variant<Holder<Incomplete>*, int> v = nullptr;
- std::visit([](auto){}, v);
- std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
+template <class T>
+struct Holder {
+ T t;
+};
+
+constexpr bool test(bool do_it) {
+ if (do_it) {
+ std::variant<Holder<Incomplete>*, int> v = nullptr;
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit([](auto) {});
+ v.visit([](auto) -> Holder<Incomplete>* { return nullptr; });
+ v.visit<void>([](auto) {});
+ v.visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; });
+ }
+#endif
+
+ // non-member
+ {
+ 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);
+ std::visit<void>([](auto) {}, v);
+ std::visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
#endif
}
- return true;
+ }
+ return true;
}
-int main(int, char**)
-{
- test(true);
+int main(int, char**) {
+ test(true);
#if TEST_STD_VER > 17
- static_assert(test(true));
+ static_assert(test(true));
#endif
- return 0;
+ return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 3fac6b21f2682a..72c9ca22802194 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -9,6 +9,13 @@
// UNSUPPORTED: c++03, c++11, c++14
// <variant>
+
+// class variant;
+// template<class Self, class Visitor>
+// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
+// template<class R, class Self, class Visitor>
+// constexpr R visit(this Self&&, Visitor&&); // since C++26
+
// template <class Visitor, class... Variants>
// constexpr see below visit(Visitor&& vis, Variants&&... vars);
@@ -26,19 +33,24 @@ void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
const Fn& cobj = obj;
+
{ // test call operator forwarding - no variant
- std::visit(obj);
- assert(Fn::check_call<>(CT_NonConst | CT_LValue));
- std::visit(cobj);
- assert(Fn::check_call<>(CT_Const | CT_LValue));
- std::visit(std::move(obj));
- assert(Fn::check_call<>(CT_NonConst | CT_RValue));
- std::visit(std::move(cobj));
- assert(Fn::check_call<>(CT_Const | CT_RValue));
+ // non-member
+ {
+ std::visit(obj);
+ assert(Fn::check_call<>(CT_NonConst | CT_LValue));
+ std::visit(cobj);
+ assert(Fn::check_call<>(CT_Const | CT_LValue));
+ std::visit(std::move(obj));
+ assert(Fn::check_call<>(CT_NonConst | CT_RValue));
+ std::visit(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);
+
#if _LIBCPP_STD_VER >= 26
// member
{
@@ -67,7 +79,7 @@ void test_call_operator_forwarding() {
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
- V v(42l);
+ V v(42L);
#if _LIBCPP_STD_VER >= 26
// member
@@ -98,59 +110,77 @@ void test_call_operator_forwarding() {
{ // 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);
+ V v(42L);
V2 v2("hello");
- std::visit(obj, v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
- std::visit(std::move(cobj), v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
+
+ // non-member
+ {
+ std::visit(obj, v, v2);
+ assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v, v2);
+ assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v, v2);
+ assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
+ std::visit(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(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
- std::visit(std::move(cobj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_RValue)));
+ V v1(42L), v2("hello"), v3(101), v4(1.1);
+
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
+ std::visit(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(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
- std::visit(std::move(cobj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
+ V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
+
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
+ std::visit(std::move(cobj), v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
+ }
}
}
+// Applies to non-member `std::visit` only.
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(obj, v);
- assert(Fn::check_call<int&>(Val));
- std::visit(obj, cv);
- assert(Fn::check_call<const int&>(Val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&&>(Val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<const int&&>(Val));
+
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<int&>(Val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<const int&>(Val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int&&>(Val));
+ std::visit(obj, std::move(cv));
+ assert(Fn::check_call<const int&&>(Val));
+ }
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{ // single argument - lvalue reference
@@ -158,6 +188,7 @@ void test_argument_forwarding() {
int x = 42;
V v(x);
const V& cv = v;
+
std::visit(obj, v);
assert(Fn::check_call<int&>(Val));
std::visit(obj, cv);
@@ -172,6 +203,7 @@ void test_argument_forwarding() {
int x = 42;
V v(std::move(x));
const V& cv = v;
+
std::visit(obj, v);
assert(Fn::check_call<int&>(Val));
std::visit(obj, cv);
@@ -184,7 +216,8 @@ void test_argument_forwarding() {
#endif
{ // multi argument - multi variant
using V = std::variant<int, std::string, long>;
- V v1(42), v2("hello"), v3(43l);
+ V v1(42), v2("hello"), v3(43L);
+
std::visit(obj, v1, v2, v3);
assert((Fn::check_call<int&, std::string&, long&>(Val)));
std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
@@ -193,6 +226,7 @@ void test_argument_forwarding() {
{
using V = std::variant<int, long, double, std::string>;
V v1(42l), v2("hello"), v3(101), v4(1.1);
+
std::visit(obj, v1, v2, v3, v4);
assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
@@ -201,6 +235,7 @@ void test_argument_forwarding() {
{
using V = std::variant<int, long, double, int*, std::string>;
V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+
std::visit(obj, v1, v2, v3, v4);
assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
@@ -212,6 +247,7 @@ 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(obj)), Fn&>);
static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
@@ -221,59 +257,114 @@ void test_return_type() {
{ // 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(obj, v)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
+ }
+#endif
+
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+ }
}
{ // 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(obj, v)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+ V v(42L);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
+ }
+#endif
+
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+ }
}
{ // 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);
+ V v(42L);
V2 v2("hello");
- static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
+
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
+ }
}
{
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(obj, v1, v2, v3, v4)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+ V v1(42L), v2("hello"), v3(101), v4(1.1);
+
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+ }
}
{
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(obj, v1, v2, v3, v4)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+ V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
+
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+ }
}
}
void test_constexpr() {
constexpr ReturnFirst obj{};
constexpr ReturnArity aobj{};
+
{
using V = std::variant<int>;
constexpr V v(42);
- static_assert(std::visit(obj, v) == 42, "");
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert(v.visit(obj) == 42); }
+#endif
+
+ //non-member
+ { static_assert(std::visit(obj, v) == 42, ""); }
}
{
using V = std::variant<short, long, char>;
- constexpr V v(42l);
- static_assert(std::visit(obj, v) == 42, "");
+ constexpr V v(42L);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert(v.visit(obj) == 42); }
+#endif
+
+ //non-member
+ { static_assert(std::visit(obj, v) == 42, ""); }
}
{
using V1 = std::variant<int>;
@@ -282,7 +373,9 @@ void test_constexpr() {
constexpr V1 v1;
constexpr V2 v2(nullptr);
constexpr V3 v3;
- static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
+
+ //non-member
+ { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); }
}
{
using V1 = std::variant<int>;
@@ -291,17 +384,23 @@ void test_constexpr() {
constexpr V1 v1;
constexpr V2 v2(nullptr);
constexpr V3 v3;
- static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
+
+ //non-member
+ { static_assert(std::visit(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(aobj, v1, v2, v3, v4) == 4, "");
+ constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
+
+ //non-member
+ { static_assert(std::visit(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(aobj, v1, v2, v3, v4) == 4, "");
+ constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
+
+ //non-member
+ { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); }
}
}
@@ -373,7 +472,14 @@ void test_caller_accepts_nonconst() {
void operator()(A&) {}
};
std::variant<A> v;
- std::visit(Visitor{}, v);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { v.visit(Visitor{}); }
+#endif
+
+ //non-member
+ { std::visit(Visitor{}, v); }
}
struct MyVariant : std::variant<short, long, float> {};
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
index eb425c07f93222..f8cdb70a28fa3b 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
@@ -9,6 +9,13 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// <variant>
+
+// class variant;
+// template<class Self, class Visitor>
+// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
+// template<class R, class Self, class Visitor>
+// constexpr R visit(this Self&&, Visitor&&); // since C++26
+
// template <class R, class Visitor, class... Variants>
// constexpr R visit(Visitor&& vis, Variants&&... vars);
@@ -26,78 +33,100 @@ template <typename ReturnType>
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn &cobj = 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));
+ // non-member
+ {
+ 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));
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ v.visit<ReturnType>(cobj);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ v.visit<ReturnType>(std::move(obj));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ v.visit<ReturnType>(std::move(cobj));
+ assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+ }
+#endif
+
+ // non-member
+ {
+ 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));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
std::visit<ReturnType>(cobj, v);
- assert(Fn::check_call<long &>(CT_Const | CT_LValue));
+ 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));
+ 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));
+ 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>;
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
}
}
@@ -109,69 +138,69 @@ void test_argument_forwarding() {
{ // single argument - value type
using V = std::variant<int>;
V v(42);
- const V &cv = v;
+ const V& cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<const int &>(Val));
+ assert(Fn::check_call<const int&>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int &&>(Val));
+ assert(Fn::check_call<int&&>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<const int &&>(Val));
+ 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;
+ using V = std::variant<int&>;
+ int x = 42;
V v(x);
- const V &cv = v;
+ const V& cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
}
{ // single argument - rvalue reference
- using V = std::variant<int &&>;
- int x = 42;
+ using V = std::variant<int&&>;
+ int x = 42;
V v(std::move(x));
- const V &cv = v;
+ const V& cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int &&>(Val));
+ assert(Fn::check_call<int&&>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<int &&>(Val));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(Val)));
}
}
@@ -179,7 +208,7 @@ template <typename ReturnType>
void test_return_type() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn &cobj = 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>);
@@ -203,8 +232,8 @@ void test_return_type() {
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>;
+ 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>);
@@ -245,7 +274,7 @@ void test_constexpr_void() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
+ using V2 = std::variant<int, char*, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
@@ -254,20 +283,20 @@ void test_constexpr_void() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
- using V3 = std::variant<void *, int, 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 *>;
+ 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 *>;
+ 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, "");
}
@@ -288,7 +317,7 @@ void test_constexpr_int() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
+ using V2 = std::variant<int, char*, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
@@ -297,20 +326,20 @@ void test_constexpr_int() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
- using V3 = std::variant<void *, int, 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 *>;
+ 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 *>;
+ 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, "");
}
@@ -320,10 +349,10 @@ template <typename ReturnType>
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
- auto test = [&](auto &&... args) {
+ auto test = [&](auto&&... args) {
try {
std::visit<ReturnType>(obj, args...);
- } catch (const std::bad_variant_access &) {
+ } catch (const std::bad_variant_access&) {
return true;
} catch (...) {
}
@@ -336,24 +365,24 @@ void test_exceptions() {
assert(test(v));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void *>;
+ 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 *>;
+ 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>;
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void*, MakeEmptyT>;
V v;
makeEmpty(v);
V2 v2;
@@ -384,8 +413,7 @@ void test_caller_accepts_nonconst() {
struct A {};
struct Visitor {
auto operator()(A&) {
- if constexpr (!std::is_void_v<ReturnType>)
- {
+ if constexpr (!std::is_void_v<ReturnType>) {
return ReturnType{};
}
}
@@ -426,9 +454,7 @@ void test_derived_from_variant() {
char valueless_by_exception;
};
- struct EvilVariant1 : std::variant<int, long, double>,
- std::tuple<int>,
- EvilVariantBase {
+ struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
using std::variant<int, long, double>::variant;
};
@@ -448,7 +474,10 @@ void test_derived_from_variant() {
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
struct Callable {
- bool operator()() const { assert(false); return false; }
+ bool operator()() const {
+ assert(false);
+ return false;
+ }
};
Callable __impl;
@@ -479,8 +508,7 @@ struct any_visitor {
}
};
-template <typename T, typename = decltype(std::visit<bool>(
- std::declval<any_visitor&>(), std::declval<T>()))>
+template <typename T, typename = decltype(std::visit<bool>(std::declval<any_visitor&>(), std::declval<T>()))>
constexpr bool has_visit(int) {
return true;
}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 2f506f32f565cb..ed89c1e679015f 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1264,7 +1264,11 @@ def add_version_header(tc):
},
{
"name": "__cpp_lib_variant",
- "values": {"c++17": 202102},
+ "values": {
+ "c++17": 202102, # std::visit for classes derived from std::variant
+ # "c++20": 202106, # Fully constexpr std::variant
+ # "c++26": 202306, # Member visit
+ },
"headers": ["variant"],
},
{
>From a52349b46a758bf8d0ba0d46ef036ff1901a1e82 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 25 Dec 2023 13:13:36 +0200
Subject: [PATCH 05/28] Implemented missing `visit` constraint + test
---
libcxx/include/variant | 4 +--
.../variant/variant.visit/visit.pass.cpp | 33 +++++++++++++++++++
2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 0da61901ce35ff..4c9b04942f2779 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1282,7 +1282,7 @@ public:
# if _LIBCPP_STD_VER >= 26
// [variant.visit], visitation
- template <class _Self, class _Visitor>
+ template <int=0, class _Self, class _Visitor>
constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);
template <class _R, class _Self, class _Visitor>
@@ -1552,7 +1552,7 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) {
// [variant.visit], visitation
template <class... _Types>
-template <class _Self, class _Visitor>
+template <int, class _Self, class _Visitor>
constexpr decltype(auto) variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) {
using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 72c9ca22802194..adbc131a6477ae 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -562,6 +562,38 @@ void test_sfinae() {
static_assert(has_visit<GoodVariant2>(0));
}
+template <class... Ts>
+struct overloaded : Ts... {
+ using Ts::operator()...;
+};
+
+void test_overload_ambiguity() {
+#if _LIBCPP_STD_VER >= 26
+ using V = std::variant<float, long, std::string>;
+ using namespace std::string_literals;
+ V v{"baba"s};
+
+ // member
+ v.visit(
+ overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }});
+ assert(std::get<std::string>(v) == "baba"s);
+
+ // `constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);`
+ // vs
+ // `constexpr _R visit(this _Self&& __self, _Visitor&& __visitor);`
+ v = std::move(v).visit<V>(overloaded{
+ []([[maybe_unused]] auto x) {
+ assert(false);
+ return 0;
+ },
+ [](const std::string& x) {
+ assert(x == "baba"s);
+ return x + " zmt"s;
+ }});
+ assert(std::get<std::string>(v) == "baba zmt"s);
+#endif
+}
+
int main(int, char**) {
test_call_operator_forwarding();
test_argument_forwarding();
@@ -571,6 +603,7 @@ int main(int, char**) {
test_caller_accepts_nonconst();
test_derived_from_variant();
test_sfinae();
+ test_overload_ambiguity();
return 0;
}
>From 9b7064d177f5205f5540f0c13aa33cdc93032cc8 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 27 Dec 2023 16:13:41 +0200
Subject: [PATCH 06/28] WIP: Updated visit tests
---
.../variant/variant.visit/visit.pass.cpp | 261 +++++++++++-------
.../variant.visit/visit_return_type.pass.cpp | 223 ++++++++++-----
2 files changed, 321 insertions(+), 163 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index adbc131a6477ae..6aff2194fa68dd 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -163,23 +163,37 @@ void test_call_operator_forwarding() {
void test_argument_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const auto Val = CT_LValue | CT_NonConst;
+ const auto val = CT_LValue | CT_NonConst;
{ // single argument - value type
using V = std::variant<int>;
V v(42);
const V& cv = v;
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit(obj);
+ assert(Fn::check_call<const int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit(obj);
+ assert(Fn::check_call<const int&&>(val));
+ }
+#endif
+
// non-member
{
std::visit(obj, v);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int&>(val));
std::visit(obj, cv);
- assert(Fn::check_call<const int&>(Val));
+ assert(Fn::check_call<const int&>(val));
std::visit(obj, std::move(v));
- assert(Fn::check_call<int&&>(Val));
+ assert(Fn::check_call<int&&>(val));
std::visit(obj, std::move(cv));
- assert(Fn::check_call<const int&&>(Val));
+ assert(Fn::check_call<const int&&>(val));
}
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
@@ -189,14 +203,32 @@ void test_argument_forwarding() {
V v(x);
const V& cv = v;
- std::visit(obj, v);
- assert(Fn::check_call<int&>(Val));
- std::visit(obj, cv);
- assert(Fn::check_call<int&>(Val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&>(Val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<int&>(Val));
+ // # if _LIBCPP_STD_VER >= 26
+ // // member
+ // {
+ // v.visit(obj);
+ // assert(Fn::check_call<int&>(val));
+ // cv.visit(obj);
+ // assert(Fn::check_call<int&>(val));
+ // std::move(v).visit(obj);
+ // assert(Fn::check_call<int&>(val));
+ // std::move(cv).visit(obj);
+ // assert(Fn::check_call<int>(CT_NonConst));
+ // assert(false);
+ // }
+ // # endif
+
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, std::move(cv));
+ assert(Fn::check_call<int&>(val));
+ }
}
{ // single argument - rvalue reference
using V = std::variant<int&&>;
@@ -204,42 +236,54 @@ void test_argument_forwarding() {
V v(std::move(x));
const V& cv = v;
- std::visit(obj, v);
- assert(Fn::check_call<int&>(Val));
- std::visit(obj, cv);
- assert(Fn::check_call<int&>(Val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&&>(Val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<int&&>(Val));
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int&&>(val));
+ std::visit(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(obj, v1, v2, v3);
- assert((Fn::check_call<int&, std::string&, long&>(Val)));
- std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
- assert((Fn::check_call<const int&, const std::string&, long&&>(Val)));
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3);
+ assert((Fn::check_call<int&, std::string&, long&>(val)));
+ std::visit(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);
+ V v1(42L), v2("hello"), v3(101), v4(1.1);
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
- std::visit(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)));
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int&, double&>(val)));
+ std::visit(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);
+ V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
- std::visit(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)));
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(val)));
+ std::visit(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)));
+ }
}
}
@@ -249,10 +293,13 @@ void test_return_type() {
const Fn& cobj = obj;
{ // test call operator forwarding - no variant
- static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
+ }
}
{ // test call operator forwarding - single variant, single arg
using V = std::variant<int>;
@@ -351,7 +398,7 @@ void test_constexpr() {
{ static_assert(v.visit(obj) == 42); }
#endif
- //non-member
+ // non-member
{ static_assert(std::visit(obj, v) == 42, ""); }
}
{
@@ -363,7 +410,7 @@ void test_constexpr() {
{ static_assert(v.visit(obj) == 42); }
#endif
- //non-member
+ // non-member
{ static_assert(std::visit(obj, v) == 42, ""); }
}
{
@@ -374,7 +421,7 @@ void test_constexpr() {
constexpr V2 v2(nullptr);
constexpr V3 v3;
- //non-member
+ // non-member
{ static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); }
}
{
@@ -385,21 +432,21 @@ void test_constexpr() {
constexpr V2 v2(nullptr);
constexpr V3 v3;
- //non-member
+ // non-member
{ static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); }
}
{
using V = std::variant<int, long, double, int*>;
constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
- //non-member
+ // non-member
{ static_assert(std::visit(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);
- //non-member
+ // non-member
{ static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); }
}
}
@@ -407,7 +454,22 @@ void test_constexpr() {
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
- auto test = [&](auto&&... args) {
+
+# if _LIBCPP_STD_VER >= 26
+ // member
+ auto test_member = [&](auto&& v) {
+ try {
+ v.visit(obj);
+ } catch (const std::bad_variant_access&) {
+ return true;
+ } catch (...) {
+ }
+ return false;
+ };
+# endif
+
+ // non-member
+ auto test_nonmember = [&](auto&&... args) {
try {
std::visit(obj, args...);
} catch (const std::bad_variant_access&) {
@@ -416,11 +478,16 @@ void test_exceptions() {
}
return false;
};
+
{
using V = std::variant<int, MakeEmptyT>;
V v;
+# if _LIBCPP_STD_VER >= 26
+ makeEmpty(v);
+ assert(test_member(v));
+# endif
makeEmpty(v);
- assert(test(v));
+ assert(test_nonmember(v));
}
{
using V = std::variant<int, MakeEmptyT>;
@@ -428,7 +495,7 @@ void test_exceptions() {
V v;
makeEmpty(v);
V2 v2("hello");
- assert(test(v, v2));
+ assert(test_nonmember(v, v2));
}
{
using V = std::variant<int, MakeEmptyT>;
@@ -436,7 +503,7 @@ void test_exceptions() {
V v;
makeEmpty(v);
V2 v2("hello");
- assert(test(v2, v));
+ assert(test_nonmember(v2, v));
}
{
using V = std::variant<int, MakeEmptyT>;
@@ -445,13 +512,13 @@ void test_exceptions() {
makeEmpty(v);
V2 v2;
makeEmpty(v2);
- assert(test(v, v2));
+ assert(test_nonmember(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));
+ assert(test_nonmember(v1, v2, v3, v4));
}
{
using V = std::variant<int, long, double, long long, MakeEmptyT>;
@@ -460,7 +527,7 @@ void test_exceptions() {
makeEmpty(v2);
makeEmpty(v3);
makeEmpty(v4);
- assert(test(v1, v2, v3, v4));
+ assert(test_nonmember(v1, v2, v3, v4));
}
#endif
}
@@ -478,7 +545,7 @@ void test_caller_accepts_nonconst() {
{ v.visit(Visitor{}); }
#endif
- //non-member
+ // non-member
{ std::visit(Visitor{}, v); }
}
@@ -494,11 +561,26 @@ void get(const MyVariant&) {
void test_derived_from_variant() {
auto v1 = MyVariant{42};
const auto cv1 = MyVariant{142};
- std::visit([](auto x) { assert(x == 42); }, v1);
- std::visit([](auto x) { assert(x == 142); }, cv1);
- std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});
- std::visit([](auto x) { assert(x == 42); }, std::move(v1));
- std::visit([](auto x) { assert(x == 142); }, std::move(cv1));
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v1.visit([](auto x) { assert(x == 42); });
+ cv1.visit([](auto x) { assert(x == 142); });
+ MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); });
+ std::move(v1).visit([](auto x) { assert(x == 42); });
+ std::move(cv1).visit([](auto x) { assert(x == 142); });
+ }
+#endif
+
+ // non-member
+ {
+ std::visit([](auto x) { assert(x == 42); }, v1);
+ std::visit([](auto x) { assert(x == 142); }, cv1);
+ std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});
+ std::visit([](auto x) { assert(x == 42); }, std::move(v1));
+ std::visit([](auto x) { assert(x == 142); }, std::move(cv1));
+ }
// Check that visit does not take index nor valueless_by_exception members from the base class.
struct EvilVariantBase {
@@ -510,8 +592,19 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
- std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
- std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ EvilVariant1{12}.visit([](auto x) { assert(x == 12); });
+ EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); });
+ }
+#endif
+
+ // non-member
+ {
+ std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
+ std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});
+ }
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
@@ -529,8 +622,19 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
- std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
- std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ EvilVariant2{12}.visit([](auto x) { assert(x == 12); });
+ EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); });
+ }
+#endif
+
+ // non-member
+ {
+ std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
+ std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});
+ }
}
struct any_visitor {
@@ -562,38 +666,6 @@ void test_sfinae() {
static_assert(has_visit<GoodVariant2>(0));
}
-template <class... Ts>
-struct overloaded : Ts... {
- using Ts::operator()...;
-};
-
-void test_overload_ambiguity() {
-#if _LIBCPP_STD_VER >= 26
- using V = std::variant<float, long, std::string>;
- using namespace std::string_literals;
- V v{"baba"s};
-
- // member
- v.visit(
- overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }});
- assert(std::get<std::string>(v) == "baba"s);
-
- // `constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);`
- // vs
- // `constexpr _R visit(this _Self&& __self, _Visitor&& __visitor);`
- v = std::move(v).visit<V>(overloaded{
- []([[maybe_unused]] auto x) {
- assert(false);
- return 0;
- },
- [](const std::string& x) {
- assert(x == "baba"s);
- return x + " zmt"s;
- }});
- assert(std::get<std::string>(v) == "baba zmt"s);
-#endif
-}
-
int main(int, char**) {
test_call_operator_forwarding();
test_argument_forwarding();
@@ -603,7 +675,6 @@ int main(int, char**) {
test_caller_accepts_nonconst();
test_derived_from_variant();
test_sfinae();
- test_overload_ambiguity();
return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
index f8cdb70a28fa3b..db4fb1961c48ec 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
@@ -81,52 +81,82 @@ void test_call_operator_forwarding() {
{ // 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));
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+ v.visit<ReturnType>(cobj);
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ v.visit<ReturnType>(std::move(obj));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+ v.visit<ReturnType>(std::move(cobj));
+ assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+ }
+#endif
+
+ // non-member
+ {
+ 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)));
+
+ // non-member
+ {
+ 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)));
+
+ // non-member
+ {
+ 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)));
+
+ // non-member
+ {
+ 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)));
+ }
}
}
@@ -135,18 +165,23 @@ 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));
+
+ // non-member
+ {
+ 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
@@ -154,53 +189,73 @@ void test_argument_forwarding() {
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));
+
+ // non-member
+ {
+ 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));
+
+ // non-member
+ {
+ 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)));
+
+ // non-member
+ {
+ 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)));
+
+ // non-member
+ {
+ 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)));
+
+ // non-member
+ {
+ 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)));
+ }
}
}
@@ -209,6 +264,7 @@ 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>);
@@ -525,6 +581,36 @@ void test_sfinae() {
static_assert(!has_visit<BadVariant>(int()));
}
+template <class... Ts>
+struct overloaded : Ts... {
+ using Ts::operator()...;
+};
+
+void test_overload_ambiguity() {
+#if _LIBCPP_STD_VER >= 26
+ using V = std::variant<float, long, std::string>;
+ using namespace std::string_literals;
+ V v{"baba"s};
+
+ // member
+ v.visit(
+ overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }});
+ assert(std::get<std::string>(v) == "baba"s);
+
+ // Test the constraint.
+ v = std::move(v).visit<V>(overloaded{
+ []([[maybe_unused]] auto x) {
+ assert(false);
+ return 0;
+ },
+ [](const std::string& x) {
+ assert(x == "baba"s);
+ return x + " zmt"s;
+ }});
+ assert(std::get<std::string>(v) == "baba zmt"s);
+#endif
+}
+
int main(int, char**) {
test_call_operator_forwarding<void>();
test_argument_forwarding<void>();
@@ -541,6 +627,7 @@ int main(int, char**) {
test_constexpr_explicit_side_effect();
test_derived_from_variant();
test_sfinae();
+ test_overload_ambiguity();
return 0;
}
>From 2d47529005c5f4444396b039f2f889cf86835d75 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 27 Dec 2023 16:35:24 +0200
Subject: [PATCH 07/28] WIP: tests
---
.../variant/variant.visit/visit.pass.cpp | 42 ++--
.../variant.visit/visit_return_type.pass.cpp | 194 ++++++++++++------
2 files changed, 155 insertions(+), 81 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 6aff2194fa68dd..9eea5f60e31388 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -203,20 +203,20 @@ void test_argument_forwarding() {
V v(x);
const V& cv = v;
- // # if _LIBCPP_STD_VER >= 26
- // // member
- // {
- // v.visit(obj);
- // assert(Fn::check_call<int&>(val));
- // cv.visit(obj);
- // assert(Fn::check_call<int&>(val));
- // std::move(v).visit(obj);
- // assert(Fn::check_call<int&>(val));
- // std::move(cv).visit(obj);
- // assert(Fn::check_call<int>(CT_NonConst));
- // assert(false);
- // }
- // # endif
+# if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(cv).visit(obj);
+ assert(Fn::check_call<int&>(val));
+ assert(false);
+ }
+# endif
// non-member
{
@@ -236,6 +236,20 @@ void test_argument_forwarding() {
V v(std::move(x));
const V& cv = v;
+# if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cvstd::visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit(obj);
+ assert(Fn::check_call<int&&>(val));
+ }
+# endif
+
// non-member
{
std::visit(obj, v);
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
index db4fb1961c48ec..31d7665d6b3ae4 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
@@ -29,6 +29,36 @@
#include "test_macros.h"
#include "variant_test_helpers.h"
+template <class... Ts>
+struct overloaded : Ts... {
+ using Ts::operator()...;
+};
+
+void test_overload_ambiguity() {
+#if _LIBCPP_STD_VER >= 26
+ using V = std::variant<float, long, std::string>;
+ using namespace std::string_literals;
+ V v{"baba"s};
+
+ // member
+ v.visit(
+ overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }});
+ assert(std::get<std::string>(v) == "baba"s);
+
+ // Test the constraint.
+ v = std::move(v).visit<V>(overloaded{
+ []([[maybe_unused]] auto x) {
+ assert(false);
+ return 0;
+ },
+ [](const std::string& x) {
+ assert(x == "baba"s);
+ return x + " zmt"s;
+ }});
+ assert(std::get<std::string>(v) == "baba zmt"s);
+#endif
+}
+
template <typename ReturnType>
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
@@ -80,7 +110,7 @@ void test_call_operator_forwarding() {
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
- V v(42l);
+ V v(42L);
#if _LIBCPP_STD_VER >= 26
// member
@@ -111,7 +141,7 @@ void test_call_operator_forwarding() {
{ // 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);
+ V v(42L);
V2 v2("hello");
// non-member
@@ -128,7 +158,7 @@ void test_call_operator_forwarding() {
}
{
using V = std::variant<int, long, double, std::string>;
- V v1(42l), v2("hello"), v3(101), v4(1.1);
+ V v1(42L), v2("hello"), v3(101), v4(1.1);
// non-member
{
@@ -144,7 +174,7 @@ void test_call_operator_forwarding() {
}
{
using V = std::variant<int, long, double, int*, std::string>;
- V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+ V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
// non-member
{
@@ -164,23 +194,37 @@ template <typename ReturnType>
void test_argument_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const auto Val = CT_LValue | CT_NonConst;
+ const auto val = CT_LValue | CT_NonConst;
{ // single argument - value type
using V = std::variant<int>;
V v(42);
const V& cv = v;
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<const int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ assert(Fn::check_call<const int&&>(val));
+ }
+#endif
+
// non-member
{
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int&>(val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<const int&>(Val));
+ assert(Fn::check_call<const int&>(val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int&&>(Val));
+ assert(Fn::check_call<int&&>(val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<const int&&>(Val));
+ assert(Fn::check_call<const int&&>(val));
}
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
@@ -190,16 +234,30 @@ void test_argument_forwarding() {
V v(x);
const V& cv = v;
+# if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ }
+# endif
+
// non-member
{
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int&>(val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int&>(val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int&>(val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int&>(val));
}
}
{ // single argument - rvalue reference
@@ -208,53 +266,67 @@ void test_argument_forwarding() {
V v(std::move(x));
const V& cv = v;
+# if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&&>(val));
+ }
+# endif
+
// non-member
{
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int&>(val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int&>(val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int&&>(Val));
+ assert(Fn::check_call<int&&>(val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<int&&>(Val));
+ 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);
+ V v1(42), v2("hello"), v3(43L);
// non-member
{
std::visit<ReturnType>(obj, v1, v2, v3);
- assert((Fn::check_call<int&, std::string&, long&>(Val)));
+ 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)));
+ 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);
+ V v1(42L), v2("hello"), v3(101), v4(1.1);
// non-member
{
std::visit<ReturnType>(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
+ 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)));
+ 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);
+ V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
// non-member
{
std::visit<ReturnType>(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
+ 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)));
+ assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(val)));
}
}
}
@@ -274,6 +346,7 @@ void test_return_type() {
{ // 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>);
@@ -281,7 +354,8 @@ void test_return_type() {
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
- V v(42l);
+ 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>);
@@ -290,8 +364,9 @@ void test_return_type() {
{ // 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);
+ 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>);
@@ -299,7 +374,8 @@ void test_return_type() {
}
{
using V = std::variant<int, long, double, std::string>;
- V v1(42l), v2("hello"), v3(101), v4(1.1);
+ 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>);
@@ -307,7 +383,8 @@ void test_return_type() {
}
{
using V = std::variant<int, long, double, int*, std::string>;
- V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+ 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>);
@@ -321,11 +398,13 @@ void test_constexpr_void() {
{
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);
+ constexpr V v(42L);
+
static_assert((std::visit<void>(obj, v), 42) == 42, "");
}
{
@@ -335,6 +414,7 @@ void test_constexpr_void() {
constexpr V1 v1;
constexpr V2 v2(nullptr);
constexpr V3 v3;
+
static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, "");
}
{
@@ -344,16 +424,19 @@ void test_constexpr_void() {
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);
+ 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);
+ constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
+
static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, "");
}
}
@@ -361,14 +444,17 @@ void test_constexpr_void() {
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);
+ constexpr V v(42L);
+
static_assert(std::visit<int>(obj, v) == 42, "");
}
{
@@ -378,6 +464,7 @@ void test_constexpr_int() {
constexpr V1 v1;
constexpr V2 v2(nullptr);
constexpr V3 v3;
+
static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, "");
}
{
@@ -387,16 +474,19 @@ void test_constexpr_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);
+ 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);
+ constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
+
static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, "");
}
}
@@ -581,37 +671,8 @@ void test_sfinae() {
static_assert(!has_visit<BadVariant>(int()));
}
-template <class... Ts>
-struct overloaded : Ts... {
- using Ts::operator()...;
-};
-
-void test_overload_ambiguity() {
-#if _LIBCPP_STD_VER >= 26
- using V = std::variant<float, long, std::string>;
- using namespace std::string_literals;
- V v{"baba"s};
-
- // member
- v.visit(
- overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }});
- assert(std::get<std::string>(v) == "baba"s);
-
- // Test the constraint.
- v = std::move(v).visit<V>(overloaded{
- []([[maybe_unused]] auto x) {
- assert(false);
- return 0;
- },
- [](const std::string& x) {
- assert(x == "baba"s);
- return x + " zmt"s;
- }});
- assert(std::get<std::string>(v) == "baba zmt"s);
-#endif
-}
-
int main(int, char**) {
+ test_overload_ambiguity();
test_call_operator_forwarding<void>();
test_argument_forwarding<void>();
test_return_type<void>();
@@ -627,7 +688,6 @@ int main(int, char**) {
test_constexpr_explicit_side_effect();
test_derived_from_variant();
test_sfinae();
- test_overload_ambiguity();
return 0;
}
>From 55516cd85c29695d58b6602e5c4f49319280cd8d Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 27 Dec 2023 17:08:46 +0200
Subject: [PATCH 08/28] WIP: more test refactoring
---
.../variant/variant.visit/visit.pass.cpp | 19 +-
.../variant.visit/visit_return_type.pass.cpp | 205 ++++++++++++++----
2 files changed, 165 insertions(+), 59 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 9eea5f60e31388..4bc35edeed3e0e 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -64,7 +64,6 @@ void test_call_operator_forwarding() {
assert(Fn::check_call<int&>(CT_Const | CT_RValue));
}
#endif
-
// non-member
{
std::visit(obj, v);
@@ -94,7 +93,6 @@ void test_call_operator_forwarding() {
assert(Fn::check_call<long&>(CT_Const | CT_RValue));
}
#endif
-
// non-member
{
std::visit(obj, v);
@@ -183,7 +181,6 @@ void test_argument_forwarding() {
assert(Fn::check_call<const int&&>(val));
}
#endif
-
// non-member
{
std::visit(obj, v);
@@ -249,7 +246,6 @@ void test_argument_forwarding() {
assert(Fn::check_call<int&&>(val));
}
# endif
-
// non-member
{
std::visit(obj, v);
@@ -328,7 +324,6 @@ void test_return_type() {
static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
}
#endif
-
// non-member
{
static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
@@ -350,7 +345,6 @@ void test_return_type() {
static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
}
#endif
-
// non-member
{
static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
@@ -411,7 +405,6 @@ void test_constexpr() {
// member
{ static_assert(v.visit(obj) == 42); }
#endif
-
// non-member
{ static_assert(std::visit(obj, v) == 42, ""); }
}
@@ -481,7 +474,6 @@ void test_exceptions() {
return false;
};
# endif
-
// non-member
auto test_nonmember = [&](auto&&... args) {
try {
@@ -498,9 +490,11 @@ void test_exceptions() {
V v;
# if _LIBCPP_STD_VER >= 26
makeEmpty(v);
+
assert(test_member(v));
# endif
makeEmpty(v);
+
assert(test_nonmember(v));
}
{
@@ -509,6 +503,7 @@ void test_exceptions() {
V v;
makeEmpty(v);
V2 v2("hello");
+
assert(test_nonmember(v, v2));
}
{
@@ -517,6 +512,7 @@ void test_exceptions() {
V v;
makeEmpty(v);
V2 v2("hello");
+
assert(test_nonmember(v2, v));
}
{
@@ -526,12 +522,14 @@ void test_exceptions() {
makeEmpty(v);
V2 v2;
makeEmpty(v2);
+
assert(test_nonmember(v, v2));
}
{
using V = std::variant<int, long, double, MakeEmptyT>;
V v1(42l), v2(101), v3(202), v4(1.1);
makeEmpty(v1);
+
assert(test_nonmember(v1, v2, v3, v4));
}
{
@@ -541,6 +539,7 @@ void test_exceptions() {
makeEmpty(v2);
makeEmpty(v3);
makeEmpty(v4);
+
assert(test_nonmember(v1, v2, v3, v4));
}
#endif
@@ -558,7 +557,6 @@ void test_caller_accepts_nonconst() {
// member
{ v.visit(Visitor{}); }
#endif
-
// non-member
{ std::visit(Visitor{}, v); }
}
@@ -586,7 +584,6 @@ void test_derived_from_variant() {
std::move(cv1).visit([](auto x) { assert(x == 142); });
}
#endif
-
// non-member
{
std::visit([](auto x) { assert(x == 42); }, v1);
@@ -613,7 +610,6 @@ void test_derived_from_variant() {
EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); });
}
#endif
-
// non-member
{
std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
@@ -643,7 +639,6 @@ void test_derived_from_variant() {
EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); });
}
#endif
-
// non-member
{
std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
index 31d7665d6b3ae4..34d90c96e43f2e 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
@@ -95,7 +95,6 @@ void test_call_operator_forwarding() {
assert(Fn::check_call<int&>(CT_Const | CT_RValue));
}
#endif
-
// non-member
{
std::visit<ReturnType>(obj, v);
@@ -338,28 +337,57 @@ void test_return_type() {
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>);
+ // non-member
+ {
+ 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>);
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
+ }
+#endif
+
+ // non-member
+ {
+ 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>);
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
+ }
+#endif
+
+ // non-member
+ {
+ 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>;
@@ -367,28 +395,37 @@ void test_return_type() {
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>);
+ // non-member
+ {
+ 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>);
+ // non-member
+ {
+ 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>);
+ // non-member
+ {
+ 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>);
+ }
}
}
@@ -399,13 +436,25 @@ void test_constexpr_void() {
using V = std::variant<int>;
constexpr V v(42);
- static_assert((std::visit<void>(obj, v), 42) == 42, "");
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert((v.visit<void>(obj), 42) == 42); }
+#endif
+
+ // non-member
+ { 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, "");
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert((v.visit<void>(obj), 42) == 42); }
+#endif
+
+ // non-member
+ { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
}
{
using V1 = std::variant<int>;
@@ -415,7 +464,8 @@ void test_constexpr_void() {
constexpr V2 v2(nullptr);
constexpr V3 v3;
- static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, "");
+ // non-member
+ { static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); }
}
{
using V1 = std::variant<int>;
@@ -425,19 +475,21 @@ void test_constexpr_void() {
constexpr V2 v2(nullptr);
constexpr V3 v3;
- static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, "");
+ // non-member
+ { 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, "");
+ // non-member
+ { 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, "");
+ // non-member
+ { static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); }
}
}
@@ -449,13 +501,25 @@ void test_constexpr_int() {
using V = std::variant<int>;
constexpr V v(42);
- static_assert(std::visit<int>(obj, v) == 42, "");
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert(v.visit<int>(obj) == 42); }
+#endif
+
+ // non-member
+ { 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, "");
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert(v.visit<int>(obj) == 42); }
+#endif
+
+ // non-member
+ { static_assert(std::visit<int>(obj, v) == 42, ""); }
}
{
using V1 = std::variant<int>;
@@ -465,7 +529,8 @@ void test_constexpr_int() {
constexpr V2 v2(nullptr);
constexpr V3 v3;
- static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, "");
+ // non-member
+ { static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); }
}
{
using V1 = std::variant<int>;
@@ -475,19 +540,22 @@ void test_constexpr_int() {
constexpr V2 v2(nullptr);
constexpr V3 v3;
- static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, "");
+ // non-member
+ { 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, "");
+ // non-member
+ { 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, "");
+ // non-member
+ { static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); }
}
}
@@ -495,7 +563,22 @@ template <typename ReturnType>
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
- auto test = [&](auto&&... args) {
+
+# if _LIBCPP_STD_VER >= 26
+ // member
+ auto test_member = [&](auto&& v) {
+ try {
+ v.template visit<ReturnType>(obj);
+ } catch (const std::bad_variant_access&) {
+ return true;
+ } catch (...) {
+ }
+ return false;
+ };
+# endif
+
+ // non-member
+ auto test_nonmember = [&](auto&&... args) {
try {
std::visit<ReturnType>(obj, args...);
} catch (const std::bad_variant_access&) {
@@ -504,11 +587,18 @@ void test_exceptions() {
}
return false;
};
+
{
using V = std::variant<int, MakeEmptyT>;
V v;
+# if _LIBCPP_STD_VER >= 26
+ makeEmpty(v);
+
+ assert(test_member(v));
+# endif
makeEmpty(v);
- assert(test(v));
+
+ assert(test_nonmember(v));
}
{
using V = std::variant<int, MakeEmptyT>;
@@ -516,7 +606,8 @@ void test_exceptions() {
V v;
makeEmpty(v);
V2 v2("hello");
- assert(test(v, v2));
+
+ assert(test_nonmember(v, v2));
}
{
using V = std::variant<int, MakeEmptyT>;
@@ -524,7 +615,8 @@ void test_exceptions() {
V v;
makeEmpty(v);
V2 v2("hello");
- assert(test(v2, v));
+
+ assert(test_nonmember(v2, v));
}
{
using V = std::variant<int, MakeEmptyT>;
@@ -533,13 +625,15 @@ void test_exceptions() {
makeEmpty(v);
V2 v2;
makeEmpty(v2);
- assert(test(v, v2));
+
+ assert(test_nonmember(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));
+
+ assert(test_nonmember(v1, v2, v3, v4));
}
{
using V = std::variant<int, long, double, long long, MakeEmptyT>;
@@ -548,7 +642,8 @@ void test_exceptions() {
makeEmpty(v2);
makeEmpty(v3);
makeEmpty(v4);
- assert(test(v1, v2, v3, v4));
+
+ assert(test_nonmember(v1, v2, v3, v4));
}
#endif
}
@@ -565,13 +660,29 @@ void test_caller_accepts_nonconst() {
}
};
std::variant<A> v;
- std::visit<ReturnType>(Visitor{}, v);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { v.template visit<ReturnType>(Visitor{}); }
+#endif
+ // non-member
+ { 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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.template visit<void>([arg](int& x) constexpr { x = arg; });
+ }
+#endif
+ // non-member
+ {
+ std::visit<void>([arg](int& x) constexpr { x = arg; }, v);
+ }
return std::get<int>(v);
};
>From 5097751e32cc89cdce94c77d813f38102cd5d22b Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 27 Dec 2023 17:28:02 +0200
Subject: [PATCH 09/28] Completed: visit_return_type.pass
---
.../variant.visit/robust_against_adl.pass.cpp | 1 -
.../variant/variant.visit/visit.pass.cpp | 2 -
.../variant.visit/visit_return_type.pass.cpp | 136 +++++++++++-------
3 files changed, 87 insertions(+), 52 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
index 6f095891693867..3723037d4e6d10 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
@@ -42,7 +42,6 @@ constexpr bool test(bool do_it) {
v.visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; });
}
#endif
-
// non-member
{
std::visit([](auto) {}, v);
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 4bc35edeed3e0e..9eb2680c47ffd5 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -214,7 +214,6 @@ void test_argument_forwarding() {
assert(false);
}
# endif
-
// non-member
{
std::visit(obj, v);
@@ -416,7 +415,6 @@ void test_constexpr() {
// member
{ static_assert(v.visit(obj) == 42); }
#endif
-
// non-member
{ static_assert(std::visit(obj, v) == 42, ""); }
}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
index 34d90c96e43f2e..b0d1055973f6c7 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
@@ -124,7 +124,6 @@ void test_call_operator_forwarding() {
assert(Fn::check_call<long&>(CT_Const | CT_RValue));
}
#endif
-
// non-member
{
std::visit<ReturnType>(obj, v);
@@ -213,7 +212,6 @@ void test_argument_forwarding() {
assert(Fn::check_call<const int&&>(val));
}
#endif
-
// non-member
{
std::visit<ReturnType>(obj, v);
@@ -246,7 +244,6 @@ void test_argument_forwarding() {
assert(Fn::check_call<int&>(val));
}
# endif
-
// non-member
{
std::visit<ReturnType>(obj, v);
@@ -278,7 +275,6 @@ void test_argument_forwarding() {
assert(Fn::check_call<int&&>(val));
}
# endif
-
// non-member
{
std::visit<ReturnType>(obj, v);
@@ -358,7 +354,6 @@ void test_return_type() {
static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
}
#endif
-
// non-member
{
static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
@@ -380,7 +375,6 @@ void test_return_type() {
static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
}
#endif
-
// non-member
{
static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
@@ -440,7 +434,6 @@ void test_constexpr_void() {
// member
{ static_assert((v.visit<void>(obj), 42) == 42); }
#endif
-
// non-member
{ static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
}
@@ -452,7 +445,6 @@ void test_constexpr_void() {
// member
{ static_assert((v.visit<void>(obj), 42) == 42); }
#endif
-
// non-member
{ static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
}
@@ -488,6 +480,7 @@ void test_constexpr_void() {
{
using V = std::variant<int, long, double, long long, int*>;
constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
+
// non-member
{ static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); }
}
@@ -505,7 +498,6 @@ void test_constexpr_int() {
// member
{ static_assert(v.visit<int>(obj) == 42); }
#endif
-
// non-member
{ static_assert(std::visit<int>(obj, v) == 42, ""); }
}
@@ -517,7 +509,6 @@ void test_constexpr_int() {
// member
{ static_assert(v.visit<int>(obj) == 42); }
#endif
-
// non-member
{ static_assert(std::visit<int>(obj, v) == 42, ""); }
}
@@ -576,7 +567,6 @@ void test_exceptions() {
return false;
};
# endif
-
// non-member
auto test_nonmember = [&](auto&&... args) {
try {
@@ -630,14 +620,14 @@ void test_exceptions() {
}
{
using V = std::variant<int, long, double, MakeEmptyT>;
- V v1(42l), v2(101), v3(202), v4(1.1);
+ V v1(42L), v2(101), v3(202), v4(1.1);
makeEmpty(v1);
assert(test_nonmember(v1, v2, v3, v4));
}
{
using V = std::variant<int, long, double, long long, MakeEmptyT>;
- V v1(42l), v2(101), v3(202), v4(1.1);
+ V v1(42L), v2(101), v3(202), v4(1.1);
makeEmpty(v1);
makeEmpty(v2);
makeEmpty(v3);
@@ -692,18 +682,34 @@ void test_constexpr_explicit_side_effect() {
void test_derived_from_variant() {
struct MyVariant : std::variant<short, long, float> {};
- std::visit<bool>(
- [](auto x) {
- assert(x == 42);
- return true;
- },
- MyVariant{42});
- std::visit<bool>(
- [](auto x) {
- assert(x == -1.3f);
- return true;
- },
- MyVariant{-1.3f});
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ MyVariant{42}.template visit<bool>([](auto x) {
+ assert(x == 42);
+ return true;
+ });
+ MyVariant{-1.3f}.template visit<bool>([](auto x) {
+ assert(x == -1.3f);
+ return true;
+ });
+ }
+#endif
+ // non-member
+ {
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 42);
+ return true;
+ },
+ MyVariant{42});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == -1.3f);
+ return true;
+ },
+ MyVariant{-1.3f});
+ }
// Check that visit does not take index nor valueless_by_exception members from the base class.
struct EvilVariantBase {
@@ -715,18 +721,34 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
- std::visit<bool>(
- [](auto x) {
- assert(x == 12);
- return true;
- },
- EvilVariant1{12});
- std::visit<bool>(
- [](auto x) {
- assert(x == 12.3);
- return true;
- },
- EvilVariant1{12.3});
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ EvilVariant1{12}.template visit<bool>([](auto x) {
+ assert(x == 12);
+ return true;
+ });
+ EvilVariant1{12.3}.template visit<bool>([](auto x) {
+ assert(x == 12.3);
+ return true;
+ });
+ }
+#endif
+ // non-member
+ {
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12);
+ return true;
+ },
+ EvilVariant1{12});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12.3);
+ return true;
+ },
+ EvilVariant1{12.3});
+ }
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
@@ -744,18 +766,34 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
- std::visit<bool>(
- [](auto x) {
- assert(x == 12);
- return true;
- },
- EvilVariant2{12});
- std::visit<bool>(
- [](auto x) {
- assert(x == 12.3);
- return true;
- },
- EvilVariant2{12.3});
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ EvilVariant2{12}.template visit<bool>([](auto x) {
+ assert(x == 12);
+ return true;
+ });
+ EvilVariant2{12.3}.template visit<bool>([](auto x) {
+ assert(x == 12.3);
+ return true;
+ });
+ }
+#endif
+ // non-member
+ {
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12);
+ return true;
+ },
+ EvilVariant2{12});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12.3);
+ return true;
+ },
+ EvilVariant2{12.3});
+ }
}
struct any_visitor {
>From 653ec7af66441bf9f9885622cec12c48322767b8 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 27 Dec 2023 17:32:53 +0200
Subject: [PATCH 10/28] Syn cleanup
---
.../variant/variant.visit/robust_against_adl.pass.cpp | 2 +-
.../test/std/utilities/variant/variant.visit/visit.pass.cpp | 4 +---
.../variant/variant.visit/visit_return_type.pass.cpp | 2 --
3 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
index 3723037d4e6d10..3bd305a7c62c17 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
@@ -12,7 +12,7 @@
// class variant;
// template<class Self, class Visitor>
-// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
+// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
// template<class R, class Self, class Visitor>
// constexpr R visit(this Self&&, Visitor&&); // since C++26
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 9eb2680c47ffd5..8781174ff7d669 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -12,9 +12,7 @@
// class variant;
// template<class Self, class Visitor>
-// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
-// template<class R, class Self, class Visitor>
-// constexpr R visit(this Self&&, Visitor&&); // since C++26
+// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
// template <class Visitor, class... Variants>
// constexpr see below visit(Visitor&& vis, Variants&&... vars);
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
index b0d1055973f6c7..1c73d34cacd87f 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
@@ -11,8 +11,6 @@
// <variant>
// class variant;
-// template<class Self, class Visitor>
-// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
// template<class R, class Self, class Visitor>
// constexpr R visit(this Self&&, Visitor&&); // since C++26
>From 9126f034eaa28d568683d3d5e3b4e91fcf014aab Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 27 Dec 2023 17:53:59 +0200
Subject: [PATCH 11/28] Fixed formatting
---
libcxx/utils/generate_feature_test_macro_components.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index ed89c1e679015f..1944591136cbb6 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1265,9 +1265,9 @@ def add_version_header(tc):
{
"name": "__cpp_lib_variant",
"values": {
- "c++17": 202102, # std::visit for classes derived from std::variant
- # "c++20": 202106, # Fully constexpr std::variant
- # "c++26": 202306, # Member visit
+ "c++17": 202102, # std::visit for classes derived from std::variant
+ # "c++20": 202106, # Fully constexpr std::variant
+ # "c++26": 202306, # Member visit
},
"headers": ["variant"],
},
>From ae8a8d6525320f6a5d653dfb79700cfa4e75f84a Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 08:19:26 +0200
Subject: [PATCH 12/28] Restored original files
---
.../variant.visit/member.visit.pass.cpp | 685 ++++++++++++++
.../member.visit.robust_against_adl.pass.cpp | 64 ++
.../member.visit_return_type.pass.cpp | 840 ++++++++++++++++++
.../variant.visit/robust_against_adl.pass.cpp | 53 +-
.../variant/variant.visit/visit.pass.cpp | 606 ++++---------
.../variant.visit/visit_return_type.pass.cpp | 768 +++++-----------
6 files changed, 2006 insertions(+), 1010 deletions(-)
create mode 100644 libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
create mode 100644 libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp
create mode 100644 libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
new file mode 100644
index 00000000000000..8781174ff7d669
--- /dev/null
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
@@ -0,0 +1,685 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <variant>
+
+// class variant;
+// template<class Self, class Visitor>
+// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
+
+// template <class Visitor, class... Variants>
+// constexpr see below 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"
+
+void test_call_operator_forwarding() {
+ using Fn = ForwardingCallObject;
+ Fn obj{};
+ const Fn& cobj = obj;
+
+ { // test call operator forwarding - no variant
+ // non-member
+ {
+ std::visit(obj);
+ assert(Fn::check_call<>(CT_NonConst | CT_LValue));
+ std::visit(cobj);
+ assert(Fn::check_call<>(CT_Const | CT_LValue));
+ std::visit(std::move(obj));
+ assert(Fn::check_call<>(CT_NonConst | CT_RValue));
+ std::visit(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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ v.visit(cobj);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ v.visit(std::move(obj));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ v.visit(std::move(cobj));
+ assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+ }
+#endif
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ std::visit(cobj, v);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ std::visit(std::move(obj), v);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ std::visit(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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+ v.visit(cobj);
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ v.visit(std::move(obj));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+ v.visit(std::move(cobj));
+ assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+ }
+#endif
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+ std::visit(cobj, v);
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ std::visit(std::move(obj), v);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+ std::visit(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");
+
+ // non-member
+ {
+ std::visit(obj, v, v2);
+ assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v, v2);
+ assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v, v2);
+ assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
+ std::visit(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);
+
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
+ std::visit(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);
+
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
+ std::visit(std::move(cobj), v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
+ }
+ }
+}
+
+// Applies to non-member `std::visit` only.
+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;
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit(obj);
+ assert(Fn::check_call<const int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit(obj);
+ assert(Fn::check_call<const int&&>(val));
+ }
+#endif
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<const int&>(val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int&&>(val));
+ std::visit(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;
+
+# if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(cv).visit(obj);
+ assert(Fn::check_call<int&>(val));
+ assert(false);
+ }
+# endif
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int&>(val));
+ std::visit(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;
+
+# if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cvstd::visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit(obj);
+ assert(Fn::check_call<int&&>(val));
+ }
+# endif
+ // non-member
+ {
+ std::visit(obj, v);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<int&>(val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int&&>(val));
+ std::visit(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);
+
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3);
+ assert((Fn::check_call<int&, std::string&, long&>(val)));
+ std::visit(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);
+
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int&, double&>(val)));
+ std::visit(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);
+
+ // non-member
+ {
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(val)));
+ std::visit(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)));
+ }
+ }
+}
+
+void test_return_type() {
+ using Fn = ForwardingCallObject;
+ Fn obj{};
+ const Fn& cobj = obj;
+
+ { // test call operator forwarding - no variant
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
+ }
+ }
+ { // test call operator forwarding - single variant, single arg
+ using V = std::variant<int>;
+ V v(42);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
+ }
+#endif
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+ }
+ }
+ { // test call operator forwarding - single variant, multi arg
+ using V = std::variant<int, long, double>;
+ V v(42L);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
+ }
+#endif
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+ }
+ }
+ { // 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");
+
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
+ }
+ }
+ {
+ using V = std::variant<int, long, double, std::string>;
+ V v1(42L), v2("hello"), v3(101), v4(1.1);
+
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+ }
+ }
+ {
+ using V = std::variant<int, long, double, int*, std::string>;
+ V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
+
+ // non-member
+ {
+ static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+ }
+ }
+}
+
+void test_constexpr() {
+ constexpr ReturnFirst obj{};
+ constexpr ReturnArity aobj{};
+
+ {
+ using V = std::variant<int>;
+ constexpr V v(42);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert(v.visit(obj) == 42); }
+#endif
+ // non-member
+ { static_assert(std::visit(obj, v) == 42, ""); }
+ }
+ {
+ using V = std::variant<short, long, char>;
+ constexpr V v(42L);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert(v.visit(obj) == 42); }
+#endif
+ // non-member
+ { static_assert(std::visit(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;
+
+ // non-member
+ { static_assert(std::visit(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;
+
+ // non-member
+ { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); }
+ }
+ {
+ using V = std::variant<int, long, double, int*>;
+ constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
+
+ // non-member
+ { static_assert(std::visit(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);
+
+ // non-member
+ { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); }
+ }
+}
+
+void test_exceptions() {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ ReturnArity obj{};
+
+# if _LIBCPP_STD_VER >= 26
+ // member
+ auto test_member = [&](auto&& v) {
+ try {
+ v.visit(obj);
+ } catch (const std::bad_variant_access&) {
+ return true;
+ } catch (...) {
+ }
+ return false;
+ };
+# endif
+ // non-member
+ auto test_nonmember = [&](auto&&... args) {
+ try {
+ std::visit(obj, args...);
+ } catch (const std::bad_variant_access&) {
+ return true;
+ } catch (...) {
+ }
+ return false;
+ };
+
+ {
+ using V = std::variant<int, MakeEmptyT>;
+ V v;
+# if _LIBCPP_STD_VER >= 26
+ makeEmpty(v);
+
+ assert(test_member(v));
+# endif
+ makeEmpty(v);
+
+ assert(test_nonmember(v));
+ }
+ {
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void*>;
+ V v;
+ makeEmpty(v);
+ V2 v2("hello");
+
+ assert(test_nonmember(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_nonmember(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_nonmember(v, v2));
+ }
+ {
+ using V = std::variant<int, long, double, MakeEmptyT>;
+ V v1(42l), v2(101), v3(202), v4(1.1);
+ makeEmpty(v1);
+
+ assert(test_nonmember(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_nonmember(v1, v2, v3, v4));
+ }
+#endif
+}
+
+// See https://llvm.org/PR31916
+void test_caller_accepts_nonconst() {
+ struct A {};
+ struct Visitor {
+ void operator()(A&) {}
+ };
+ std::variant<A> v;
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { v.visit(Visitor{}); }
+#endif
+ // non-member
+ { std::visit(Visitor{}, v); }
+}
+
+struct MyVariant : std::variant<short, long, float> {};
+
+namespace std {
+template <std::size_t Index>
+void get(const MyVariant&) {
+ assert(false);
+}
+} // namespace std
+
+void test_derived_from_variant() {
+ auto v1 = MyVariant{42};
+ const auto cv1 = MyVariant{142};
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v1.visit([](auto x) { assert(x == 42); });
+ cv1.visit([](auto x) { assert(x == 142); });
+ MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); });
+ std::move(v1).visit([](auto x) { assert(x == 42); });
+ std::move(cv1).visit([](auto x) { assert(x == 142); });
+ }
+#endif
+ // non-member
+ {
+ std::visit([](auto x) { assert(x == 42); }, v1);
+ std::visit([](auto x) { assert(x == 142); }, cv1);
+ std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});
+ std::visit([](auto x) { assert(x == 42); }, std::move(v1));
+ std::visit([](auto x) { assert(x == 142); }, std::move(cv1));
+ }
+
+ // Check that visit does not take index nor valueless_by_exception members from the base class.
+ struct EvilVariantBase {
+ int index;
+ char valueless_by_exception;
+ };
+
+ struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
+ using std::variant<int, long, double>::variant;
+ };
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ EvilVariant1{12}.visit([](auto x) { assert(x == 12); });
+ EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); });
+ }
+#endif
+ // non-member
+ {
+ std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
+ std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});
+ }
+
+ // Check that visit unambiguously picks the variant, even if the other base has __impl member.
+ struct ImplVariantBase {
+ struct Callable {
+ bool operator()() const {
+ assert(false);
+ return false;
+ }
+ };
+
+ Callable __impl;
+ };
+
+ struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase {
+ using std::variant<int, long, double>::variant;
+ };
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ EvilVariant2{12}.visit([](auto x) { assert(x == 12); });
+ EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); });
+ }
+#endif
+ // non-member
+ {
+ std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
+ std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});
+ }
+}
+
+struct any_visitor {
+ template <typename T>
+ void operator()(const T&) const {}
+};
+
+template <typename T, typename = decltype(std::visit(std::declval<any_visitor&>(), std::declval<T>()))>
+constexpr bool has_visit(int) {
+ return true;
+}
+
+template <typename T>
+constexpr bool has_visit(...) {
+ return false;
+}
+
+void test_sfinae() {
+ struct BadVariant : std::variant<short>, std::variant<long, float> {};
+ struct BadVariant2 : private std::variant<long, float> {};
+ struct GoodVariant : std::variant<long, float> {};
+ struct GoodVariant2 : GoodVariant {};
+
+ static_assert(!has_visit<int>(0));
+ static_assert(!has_visit<BadVariant>(0));
+ static_assert(!has_visit<BadVariant2>(0));
+ static_assert(has_visit<std::variant<int>>(0));
+ static_assert(has_visit<GoodVariant>(0));
+ static_assert(has_visit<GoodVariant2>(0));
+}
+
+int main(int, char**) {
+ test_call_operator_forwarding();
+ test_argument_forwarding();
+ test_return_type();
+ test_constexpr();
+ test_exceptions();
+ test_caller_accepts_nonconst();
+ test_derived_from_variant();
+ test_sfinae();
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp
new file mode 100644
index 00000000000000..3bd305a7c62c17
--- /dev/null
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <variant>
+
+// class variant;
+// template<class Self, class Visitor>
+// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
+// template<class R, class Self, class Visitor>
+// constexpr R visit(this Self&&, Visitor&&); // since C++26
+
+// template <class Visitor, class... Variants>
+// constexpr see below visit(Visitor&& vis, Variants&&... vars);
+
+#include <variant>
+
+#include "test_macros.h"
+
+struct Incomplete;
+template <class T>
+struct Holder {
+ T t;
+};
+
+constexpr bool test(bool do_it) {
+ if (do_it) {
+ std::variant<Holder<Incomplete>*, int> v = nullptr;
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit([](auto) {});
+ v.visit([](auto) -> Holder<Incomplete>* { return nullptr; });
+ v.visit<void>([](auto) {});
+ v.visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; });
+ }
+#endif
+ // non-member
+ {
+ 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;
+}
+
+int main(int, char**) {
+ test(true);
+#if TEST_STD_VER > 17
+ static_assert(test(true));
+#endif
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
new file mode 100644
index 00000000000000..1c73d34cacd87f
--- /dev/null
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
@@ -0,0 +1,840 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <variant>
+
+// class variant;
+// template<class R, class Self, class Visitor>
+// constexpr R visit(this Self&&, Visitor&&); // since C++26
+
+// 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 <class... Ts>
+struct overloaded : Ts... {
+ using Ts::operator()...;
+};
+
+void test_overload_ambiguity() {
+#if _LIBCPP_STD_VER >= 26
+ using V = std::variant<float, long, std::string>;
+ using namespace std::string_literals;
+ V v{"baba"s};
+
+ // member
+ v.visit(
+ overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }});
+ assert(std::get<std::string>(v) == "baba"s);
+
+ // Test the constraint.
+ v = std::move(v).visit<V>(overloaded{
+ []([[maybe_unused]] auto x) {
+ assert(false);
+ return 0;
+ },
+ [](const std::string& x) {
+ assert(x == "baba"s);
+ return x + " zmt"s;
+ }});
+ assert(std::get<std::string>(v) == "baba zmt"s);
+#endif
+}
+
+template <typename ReturnType>
+void test_call_operator_forwarding() {
+ using Fn = ForwardingCallObject;
+ Fn obj{};
+ const Fn& cobj = obj;
+
+ { // test call operator forwarding - no variant
+ // non-member
+ {
+ 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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ v.visit<ReturnType>(cobj);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ v.visit<ReturnType>(std::move(obj));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ v.visit<ReturnType>(std::move(cobj));
+ assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+ }
+#endif
+ // non-member
+ {
+ 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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+ v.visit<ReturnType>(cobj);
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ v.visit<ReturnType>(std::move(obj));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+ v.visit<ReturnType>(std::move(cobj));
+ assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+ }
+#endif
+ // non-member
+ {
+ 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");
+
+ // non-member
+ {
+ 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);
+
+ // non-member
+ {
+ 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);
+
+ // non-member
+ {
+ 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;
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<const int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ assert(Fn::check_call<const int&&>(val));
+ }
+#endif
+ // non-member
+ {
+ 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;
+
+# if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ }
+# endif
+ // non-member
+ {
+ 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;
+
+# if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&&>(val));
+ }
+# endif
+ // non-member
+ {
+ 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);
+
+ // non-member
+ {
+ 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);
+
+ // non-member
+ {
+ 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);
+
+ // non-member
+ {
+ 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
+ // non-member
+ {
+ 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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
+ }
+#endif
+ // non-member
+ {
+ 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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
+ }
+#endif
+ // non-member
+ {
+ 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");
+
+ // non-member
+ {
+ 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);
+
+ // non-member
+ {
+ 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);
+
+ // non-member
+ {
+ 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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert((v.visit<void>(obj), 42) == 42); }
+#endif
+ // non-member
+ { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
+ }
+ {
+ using V = std::variant<short, long, char>;
+ constexpr V v(42L);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert((v.visit<void>(obj), 42) == 42); }
+#endif
+ // non-member
+ { 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;
+
+ // non-member
+ { 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;
+
+ // non-member
+ { 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);
+
+ // non-member
+ { 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);
+
+ // non-member
+ { 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);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert(v.visit<int>(obj) == 42); }
+#endif
+ // non-member
+ { static_assert(std::visit<int>(obj, v) == 42, ""); }
+ }
+ {
+ using V = std::variant<short, long, char>;
+ constexpr V v(42L);
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { static_assert(v.visit<int>(obj) == 42); }
+#endif
+ // non-member
+ { 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;
+
+ // non-member
+ { 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;
+
+ // non-member
+ { 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);
+
+ // non-member
+ { 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);
+
+ // non-member
+ { static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); }
+ }
+}
+
+template <typename ReturnType>
+void test_exceptions() {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ ReturnArity obj{};
+
+# if _LIBCPP_STD_VER >= 26
+ // member
+ auto test_member = [&](auto&& v) {
+ try {
+ v.template visit<ReturnType>(obj);
+ } catch (const std::bad_variant_access&) {
+ return true;
+ } catch (...) {
+ }
+ return false;
+ };
+# endif
+ // non-member
+ auto test_nonmember = [&](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;
+# if _LIBCPP_STD_VER >= 26
+ makeEmpty(v);
+
+ assert(test_member(v));
+# endif
+ makeEmpty(v);
+
+ assert(test_nonmember(v));
+ }
+ {
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void*>;
+ V v;
+ makeEmpty(v);
+ V2 v2("hello");
+
+ assert(test_nonmember(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_nonmember(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_nonmember(v, v2));
+ }
+ {
+ using V = std::variant<int, long, double, MakeEmptyT>;
+ V v1(42L), v2(101), v3(202), v4(1.1);
+ makeEmpty(v1);
+
+ assert(test_nonmember(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_nonmember(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;
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ { v.template visit<ReturnType>(Visitor{}); }
+#endif
+ // non-member
+ { std::visit<ReturnType>(Visitor{}, v); }
+}
+
+void test_constexpr_explicit_side_effect() {
+ auto test_lambda = [](int arg) constexpr {
+ std::variant<int> v = 101;
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ v.template visit<void>([arg](int& x) constexpr { x = arg; });
+ }
+#endif
+ // non-member
+ {
+ std::visit<void>([arg](int& x) constexpr { x = arg; }, v);
+ }
+ return std::get<int>(v);
+ };
+
+ static_assert(test_lambda(202) == 202, "");
+}
+
+void test_derived_from_variant() {
+ struct MyVariant : std::variant<short, long, float> {};
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ MyVariant{42}.template visit<bool>([](auto x) {
+ assert(x == 42);
+ return true;
+ });
+ MyVariant{-1.3f}.template visit<bool>([](auto x) {
+ assert(x == -1.3f);
+ return true;
+ });
+ }
+#endif
+ // non-member
+ {
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 42);
+ return true;
+ },
+ MyVariant{42});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == -1.3f);
+ return true;
+ },
+ MyVariant{-1.3f});
+ }
+
+ // Check that visit does not take index nor valueless_by_exception members from the base class.
+ struct EvilVariantBase {
+ int index;
+ char valueless_by_exception;
+ };
+
+ struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
+ using std::variant<int, long, double>::variant;
+ };
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ EvilVariant1{12}.template visit<bool>([](auto x) {
+ assert(x == 12);
+ return true;
+ });
+ EvilVariant1{12.3}.template visit<bool>([](auto x) {
+ assert(x == 12.3);
+ return true;
+ });
+ }
+#endif
+ // non-member
+ {
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12);
+ return true;
+ },
+ EvilVariant1{12});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12.3);
+ return true;
+ },
+ EvilVariant1{12.3});
+ }
+
+ // Check that visit unambiguously picks the variant, even if the other base has __impl member.
+ struct ImplVariantBase {
+ struct Callable {
+ bool operator()() const {
+ assert(false);
+ return false;
+ }
+ };
+
+ Callable __impl;
+ };
+
+ struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase {
+ using std::variant<int, long, double>::variant;
+ };
+
+#if _LIBCPP_STD_VER >= 26
+ // member
+ {
+ EvilVariant2{12}.template visit<bool>([](auto x) {
+ assert(x == 12);
+ return true;
+ });
+ EvilVariant2{12.3}.template visit<bool>([](auto x) {
+ assert(x == 12.3);
+ return true;
+ });
+ }
+#endif
+ // non-member
+ {
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12);
+ return true;
+ },
+ EvilVariant2{12});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12.3);
+ return true;
+ },
+ EvilVariant2{12.3});
+ }
+}
+
+struct any_visitor {
+ template <typename T>
+ bool operator()(const T&) {
+ return true;
+ }
+};
+
+template <typename T, typename = decltype(std::visit<bool>(std::declval<any_visitor&>(), std::declval<T>()))>
+constexpr bool has_visit(int) {
+ return true;
+}
+
+template <typename T>
+constexpr bool has_visit(...) {
+ return false;
+}
+
+void test_sfinae() {
+ struct BadVariant : std::variant<short>, std::variant<long, float> {};
+
+ static_assert(has_visit<std::variant<int> >(int()));
+ static_assert(!has_visit<BadVariant>(int()));
+}
+
+int main(int, char**) {
+ test_overload_ambiguity();
+ 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();
+ test_derived_from_variant();
+ test_sfinae();
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
index 3bd305a7c62c17..6f17fa32648d41 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
@@ -9,13 +9,6 @@
// UNSUPPORTED: c++03, c++11, c++14
// <variant>
-
-// class variant;
-// template<class Self, class Visitor>
-// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
-// template<class R, class Self, class Visitor>
-// constexpr R visit(this Self&&, Visitor&&); // since C++26
-
// template <class Visitor, class... Variants>
// constexpr see below visit(Visitor&& vis, Variants&&... vars);
@@ -24,41 +17,27 @@
#include "test_macros.h"
struct Incomplete;
-template <class T>
-struct Holder {
- T t;
-};
-
-constexpr bool test(bool do_it) {
- if (do_it) {
- std::variant<Holder<Incomplete>*, int> v = nullptr;
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit([](auto) {});
- v.visit([](auto) -> Holder<Incomplete>* { return nullptr; });
- v.visit<void>([](auto) {});
- v.visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; });
- }
-#endif
- // non-member
- {
- std::visit([](auto) {}, v);
- std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
+template<class T> struct Holder { T t; };
+
+constexpr bool test(bool do_it)
+{
+ if (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);
+ std::visit<void>([](auto){}, v);
+ std::visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
#endif
}
- }
- return true;
+ return true;
}
-int main(int, char**) {
- test(true);
+int main(int, char**)
+{
+ test(true);
#if TEST_STD_VER > 17
- static_assert(test(true));
+ static_assert(test(true));
#endif
- return 0;
+ return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
index 8781174ff7d669..097b784f2bf2ce 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -9,11 +9,6 @@
// UNSUPPORTED: c++03, c++11, c++14
// <variant>
-
-// class variant;
-// template<class Self, class Visitor>
-// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
-
// template <class Visitor, class... Variants>
// constexpr see below visit(Visitor&& vis, Variants&&... vars);
@@ -30,503 +25,299 @@
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn& cobj = obj;
-
+ const Fn &cobj = obj;
{ // test call operator forwarding - no variant
- // non-member
- {
- std::visit(obj);
- assert(Fn::check_call<>(CT_NonConst | CT_LValue));
- std::visit(cobj);
- assert(Fn::check_call<>(CT_Const | CT_LValue));
- std::visit(std::move(obj));
- assert(Fn::check_call<>(CT_NonConst | CT_RValue));
- std::visit(std::move(cobj));
- assert(Fn::check_call<>(CT_Const | CT_RValue));
- }
+ std::visit(obj);
+ assert(Fn::check_call<>(CT_NonConst | CT_LValue));
+ std::visit(cobj);
+ assert(Fn::check_call<>(CT_Const | CT_LValue));
+ std::visit(std::move(obj));
+ assert(Fn::check_call<>(CT_NonConst | CT_RValue));
+ std::visit(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);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
- v.visit(cobj);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
- v.visit(std::move(obj));
- assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
- v.visit(std::move(cobj));
- assert(Fn::check_call<int&>(CT_Const | CT_RValue));
- }
-#endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
- std::visit(cobj, v);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
- std::visit(std::move(obj), v);
- assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
- std::visit(std::move(cobj), v);
- assert(Fn::check_call<int&>(CT_Const | CT_RValue));
- }
+ std::visit(obj, v);
+ assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
+ std::visit(cobj, v);
+ assert(Fn::check_call<int &>(CT_Const | CT_LValue));
+ std::visit(std::move(obj), v);
+ assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
+ std::visit(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);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
- v.visit(cobj);
- assert(Fn::check_call<long&>(CT_Const | CT_LValue));
- v.visit(std::move(obj));
- assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
- v.visit(std::move(cobj));
- assert(Fn::check_call<long&>(CT_Const | CT_RValue));
- }
-#endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
- std::visit(cobj, v);
- assert(Fn::check_call<long&>(CT_Const | CT_LValue));
- std::visit(std::move(obj), v);
- assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
- std::visit(std::move(cobj), v);
- assert(Fn::check_call<long&>(CT_Const | CT_RValue));
- }
+ V v(42l);
+ std::visit(obj, v);
+ assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
+ std::visit(cobj, v);
+ assert(Fn::check_call<long &>(CT_Const | CT_LValue));
+ std::visit(std::move(obj), v);
+ assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
+ std::visit(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);
+ using V = std::variant<int, long, double>;
+ using V2 = std::variant<int *, std::string>;
+ V v(42l);
V2 v2("hello");
-
- // non-member
- {
- std::visit(obj, v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
- std::visit(std::move(cobj), v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
- }
+ std::visit(obj, v, v2);
+ assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v, v2);
+ assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v, v2);
+ assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
+ std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
- std::visit(std::move(cobj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_RValue)));
- }
+ V v1(42l), v2("hello"), v3(101), v4(1.1);
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue)));
+ std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
- std::visit(std::move(cobj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
- }
+ V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue)));
+ std::visit(cobj, v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue)));
+ std::visit(std::move(obj), v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue)));
+ std::visit(std::move(cobj), v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));
}
}
-// Applies to non-member `std::visit` only.
void test_argument_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const auto val = CT_LValue | CT_NonConst;
-
+ const auto Val = CT_LValue | CT_NonConst;
{ // single argument - value type
using V = std::variant<int>;
V v(42);
- const V& cv = v;
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit(obj);
- assert(Fn::check_call<const int&>(val));
- std::move(v).visit(obj);
- assert(Fn::check_call<int&&>(val));
- std::move(cv).visit(obj);
- assert(Fn::check_call<const int&&>(val));
- }
-#endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, cv);
- assert(Fn::check_call<const int&>(val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&&>(val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<const int&&>(val));
- }
+ const V &cv = v;
+ std::visit(obj, v);
+ assert(Fn::check_call<int &>(Val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<const int &>(Val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int &&>(Val));
+ std::visit(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;
+ using V = std::variant<int &>;
+ int x = 42;
V v(x);
- const V& cv = v;
-
-# if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit(obj);
- assert(Fn::check_call<int&>(val));
- std::move(v).visit(obj);
- assert(Fn::check_call<int&>(val));
- std::move(cv).visit(obj);
- assert(Fn::check_call<int&>(val));
- assert(false);
- }
-# endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, cv);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&>(val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<int&>(val));
- }
+ const V &cv = v;
+ std::visit(obj, v);
+ assert(Fn::check_call<int &>(Val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<int &>(Val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int &>(Val));
+ std::visit(obj, std::move(cv));
+ assert(Fn::check_call<int &>(Val));
}
{ // single argument - rvalue reference
- using V = std::variant<int&&>;
- int x = 42;
+ using V = std::variant<int &&>;
+ int x = 42;
V v(std::move(x));
- const V& cv = v;
-
-# if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<int&>(val));
- cvstd::visit(obj);
- assert(Fn::check_call<int&>(val));
- std::move(v).visit(obj);
- assert(Fn::check_call<int&&>(val));
- std::move(cv).visit(obj);
- assert(Fn::check_call<int&&>(val));
- }
-# endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, cv);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&&>(val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<int&&>(val));
- }
+ const V &cv = v;
+ std::visit(obj, v);
+ assert(Fn::check_call<int &>(Val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<int &>(Val));
+ std::visit(obj, std::move(v));
+ assert(Fn::check_call<int &&>(Val));
+ std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3);
- assert((Fn::check_call<int&, std::string&, long&>(val)));
- std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
- assert((Fn::check_call<const int&, const std::string&, long&&>(val)));
- }
+ V v1(42), v2("hello"), v3(43l);
+ std::visit(obj, v1, v2, v3);
+ assert((Fn::check_call<int &, std::string &, long &>(Val)));
+ std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(val)));
- std::visit(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)));
- }
+ V v1(42l), v2("hello"), v3(101), v4(1.1);
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int &, double &>(Val)));
+ std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(val)));
- std::visit(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)));
- }
+ V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+ std::visit(obj, v1, v2, v3, v4);
+ assert((Fn::check_call<long &, std::string &, int *&, double &>(Val)));
+ std::visit(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)));
}
}
void test_return_type() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn& cobj = obj;
-
+ const Fn &cobj = obj;
{ // test call operator forwarding - no variant
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
- }
+ static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
}
{ // test call operator forwarding - single variant, single arg
using V = std::variant<int>;
V v(42);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
- static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
- static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
- static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
- }
-#endif
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
- }
+ static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
- V v(42L);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
- static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
- static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
- static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
- }
-#endif
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
- }
+ V v(42l);
+ static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
}
{ // 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);
+ using V = std::variant<int, long, double>;
+ using V2 = std::variant<int *, std::string>;
+ V v(42l);
V2 v2("hello");
-
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
- }
+ static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
}
{
using V = std::variant<int, long, double, std::string>;
- V v1(42L), v2("hello"), v3(101), v4(1.1);
-
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
- }
+ V v1(42l), v2("hello"), v3(101), v4(1.1);
+ static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
}
{
using V = std::variant<int, long, double, int*, std::string>;
- V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
-
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
- }
+ V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+ static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+ static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
}
}
void test_constexpr() {
constexpr ReturnFirst obj{};
constexpr ReturnArity aobj{};
-
{
using V = std::variant<int>;
constexpr V v(42);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert(v.visit(obj) == 42); }
-#endif
- // non-member
- { static_assert(std::visit(obj, v) == 42, ""); }
+ static_assert(std::visit(obj, v) == 42, "");
}
{
using V = std::variant<short, long, char>;
- constexpr V v(42L);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert(v.visit(obj) == 42); }
-#endif
- // non-member
- { static_assert(std::visit(obj, v) == 42, ""); }
+ constexpr V v(42l);
+ static_assert(std::visit(obj, v) == 42, "");
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char*, long long>;
+ 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;
-
- // non-member
- { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); }
+ static_assert(std::visit(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>;
+ 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;
-
- // non-member
- { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); }
+ static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
}
{
- using V = std::variant<int, long, double, int*>;
- constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
-
- // non-member
- { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); }
+ using V = std::variant<int, long, double, int *>;
+ constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
+ static_assert(std::visit(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);
-
- // non-member
- { static_assert(std::visit(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(aobj, v1, v2, v3, v4) == 4, "");
}
}
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
-
-# if _LIBCPP_STD_VER >= 26
- // member
- auto test_member = [&](auto&& v) {
- try {
- v.visit(obj);
- } catch (const std::bad_variant_access&) {
- return true;
- } catch (...) {
- }
- return false;
- };
-# endif
- // non-member
- auto test_nonmember = [&](auto&&... args) {
+ auto test = [&](auto &&... args) {
try {
std::visit(obj, args...);
- } catch (const std::bad_variant_access&) {
+ } catch (const std::bad_variant_access &) {
return true;
} catch (...) {
}
return false;
};
-
{
using V = std::variant<int, MakeEmptyT>;
V v;
-# if _LIBCPP_STD_VER >= 26
- makeEmpty(v);
-
- assert(test_member(v));
-# endif
makeEmpty(v);
-
- assert(test_nonmember(v));
+ assert(test(v));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*>;
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void *>;
V v;
makeEmpty(v);
V2 v2("hello");
-
- assert(test_nonmember(v, v2));
+ assert(test(v, v2));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*>;
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void *>;
V v;
makeEmpty(v);
V2 v2("hello");
-
- assert(test_nonmember(v2, v));
+ assert(test(v2, v));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*, MakeEmptyT>;
+ 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_nonmember(v, 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_nonmember(v1, v2, v3, v4));
+ assert(test(v1, v2, v3, v4));
}
{
using V = std::variant<int, long, double, long long, MakeEmptyT>;
@@ -535,8 +326,7 @@ void test_exceptions() {
makeEmpty(v2);
makeEmpty(v3);
makeEmpty(v4);
-
- assert(test_nonmember(v1, v2, v3, v4));
+ assert(test(v1, v2, v3, v4));
}
#endif
}
@@ -548,13 +338,7 @@ void test_caller_accepts_nonconst() {
void operator()(A&) {}
};
std::variant<A> v;
-
-#if _LIBCPP_STD_VER >= 26
- // member
- { v.visit(Visitor{}); }
-#endif
- // non-member
- { std::visit(Visitor{}, v); }
+ std::visit(Visitor{}, v);
}
struct MyVariant : std::variant<short, long, float> {};
@@ -567,27 +351,13 @@ void get(const MyVariant&) {
} // namespace std
void test_derived_from_variant() {
- auto v1 = MyVariant{42};
+ auto v1 = MyVariant{42};
const auto cv1 = MyVariant{142};
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v1.visit([](auto x) { assert(x == 42); });
- cv1.visit([](auto x) { assert(x == 142); });
- MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); });
- std::move(v1).visit([](auto x) { assert(x == 42); });
- std::move(cv1).visit([](auto x) { assert(x == 142); });
- }
-#endif
- // non-member
- {
- std::visit([](auto x) { assert(x == 42); }, v1);
- std::visit([](auto x) { assert(x == 142); }, cv1);
- std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});
- std::visit([](auto x) { assert(x == 42); }, std::move(v1));
- std::visit([](auto x) { assert(x == 142); }, std::move(cv1));
- }
+ std::visit([](auto x) { assert(x == 42); }, v1);
+ std::visit([](auto x) { assert(x == 142); }, cv1);
+ std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});
+ std::visit([](auto x) { assert(x == 42); }, std::move(v1));
+ std::visit([](auto x) { assert(x == 142); }, std::move(cv1));
// Check that visit does not take index nor valueless_by_exception members from the base class.
struct EvilVariantBase {
@@ -595,30 +365,19 @@ void test_derived_from_variant() {
char valueless_by_exception;
};
- struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
+ struct EvilVariant1 : std::variant<int, long, double>,
+ std::tuple<int>,
+ EvilVariantBase {
using std::variant<int, long, double>::variant;
};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- EvilVariant1{12}.visit([](auto x) { assert(x == 12); });
- EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); });
- }
-#endif
- // non-member
- {
- std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
- std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});
- }
+ std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
+ std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
struct Callable {
- bool operator()() const {
- assert(false);
- return false;
- }
+ bool operator()() const { assert(false); return false; }
};
Callable __impl;
@@ -628,18 +387,8 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- EvilVariant2{12}.visit([](auto x) { assert(x == 12); });
- EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); });
- }
-#endif
- // non-member
- {
- std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
- std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});
- }
+ std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
+ std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});
}
struct any_visitor {
@@ -647,7 +396,8 @@ struct any_visitor {
void operator()(const T&) const {}
};
-template <typename T, typename = decltype(std::visit(std::declval<any_visitor&>(), std::declval<T>()))>
+template <typename T, typename = decltype(std::visit(
+ std::declval<any_visitor&>(), std::declval<T>()))>
constexpr bool has_visit(int) {
return true;
}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
index 1c73d34cacd87f..eb425c07f93222 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
@@ -9,11 +9,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// <variant>
-
-// class variant;
-// template<class R, class Self, class Visitor>
-// constexpr R visit(this Self&&, Visitor&&); // since C++26
-
// template <class R, class Visitor, class... Variants>
// constexpr R visit(Visitor&& vis, Variants&&... vars);
@@ -27,162 +22,82 @@
#include "test_macros.h"
#include "variant_test_helpers.h"
-template <class... Ts>
-struct overloaded : Ts... {
- using Ts::operator()...;
-};
-
-void test_overload_ambiguity() {
-#if _LIBCPP_STD_VER >= 26
- using V = std::variant<float, long, std::string>;
- using namespace std::string_literals;
- V v{"baba"s};
-
- // member
- v.visit(
- overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }});
- assert(std::get<std::string>(v) == "baba"s);
-
- // Test the constraint.
- v = std::move(v).visit<V>(overloaded{
- []([[maybe_unused]] auto x) {
- assert(false);
- return 0;
- },
- [](const std::string& x) {
- assert(x == "baba"s);
- return x + " zmt"s;
- }});
- assert(std::get<std::string>(v) == "baba zmt"s);
-#endif
-}
-
template <typename ReturnType>
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn& cobj = obj;
-
+ const Fn &cobj = obj;
{ // test call operator forwarding - no variant
- // non-member
- {
- 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));
- }
+ 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);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
- v.visit<ReturnType>(cobj);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
- v.visit<ReturnType>(std::move(obj));
- assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
- v.visit<ReturnType>(std::move(cobj));
- assert(Fn::check_call<int&>(CT_Const | CT_RValue));
- }
-#endif
- // non-member
- {
- 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));
- }
+ 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);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
- v.visit<ReturnType>(cobj);
- assert(Fn::check_call<long&>(CT_Const | CT_LValue));
- v.visit<ReturnType>(std::move(obj));
- assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
- v.visit<ReturnType>(std::move(cobj));
- assert(Fn::check_call<long&>(CT_Const | CT_RValue));
- }
-#endif
- // non-member
- {
- 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));
- }
+ 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);
+ using V = std::variant<int, long, double>;
+ using V2 = std::variant<int *, std::string>;
+ V v(42l);
V2 v2("hello");
-
- // non-member
- {
- 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)));
- }
+ 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);
-
- // non-member
- {
- 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)));
- }
+ 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);
-
- // non-member
- {
- 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)));
- }
+ 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)));
}
}
@@ -190,137 +105,73 @@ template <typename ReturnType>
void test_argument_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const auto val = CT_LValue | CT_NonConst;
-
+ const auto Val = CT_LValue | CT_NonConst;
{ // single argument - value type
using V = std::variant<int>;
V v(42);
- const V& cv = v;
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit<ReturnType>(obj);
- assert(Fn::check_call<const int&>(val));
- std::move(v).visit<ReturnType>(obj);
- assert(Fn::check_call<int&&>(val));
- std::move(cv).visit<ReturnType>(obj);
- assert(Fn::check_call<const int&&>(val));
- }
-#endif
- // non-member
- {
- 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));
- }
+ 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;
+ using V = std::variant<int &>;
+ int x = 42;
V v(x);
- const V& cv = v;
-
-# if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- std::move(v).visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- std::move(cv).visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- }
-# endif
- // non-member
- {
- 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));
- }
+ 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;
+ using V = std::variant<int &&>;
+ int x = 42;
V v(std::move(x));
- const V& cv = v;
-
-# if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- std::move(v).visit<ReturnType>(obj);
- assert(Fn::check_call<int&&>(val));
- std::move(cv).visit<ReturnType>(obj);
- assert(Fn::check_call<int&&>(val));
- }
-# endif
- // non-member
- {
- 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));
- }
+ 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);
-
- // non-member
- {
- 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)));
- }
+ 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);
-
- // non-member
- {
- 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)));
- }
+ 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);
-
- // non-member
- {
- 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)));
- }
+ 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)));
}
}
@@ -328,96 +179,54 @@ template <typename ReturnType>
void test_return_type() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn& cobj = obj;
-
+ const Fn &cobj = obj;
{ // test call operator forwarding - no variant
- // non-member
- {
- 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>);
- }
+ 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);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
- }
-#endif
- // non-member
- {
- 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>);
- }
+ 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);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
- }
-#endif
- // non-member
- {
- 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>);
- }
+ 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);
+ using V = std::variant<int, long, double>;
+ using V2 = std::variant<int *, std::string>;
+ V v(42l);
V2 v2("hello");
-
- // non-member
- {
- 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>);
- }
+ 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);
-
- // non-member
- {
- 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>);
- }
+ 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);
-
- // non-member
- {
- 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>);
- }
+ 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>);
}
}
@@ -427,124 +236,83 @@ void test_constexpr_void() {
{
using V = std::variant<int>;
constexpr V v(42);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert((v.visit<void>(obj), 42) == 42); }
-#endif
- // non-member
- { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
+ static_assert((std::visit<void>(obj, v), 42) == 42, "");
}
{
using V = std::variant<short, long, char>;
- constexpr V v(42L);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert((v.visit<void>(obj), 42) == 42); }
-#endif
- // non-member
- { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
+ 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 V2 = std::variant<int, char *, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
constexpr V3 v3;
-
- // non-member
- { static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); }
+ 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>;
+ 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;
-
- // non-member
- { static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); }
+ 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);
-
- // non-member
- { static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); }
+ 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);
-
- // non-member
- { 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);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert(v.visit<int>(obj) == 42); }
-#endif
- // non-member
- { static_assert(std::visit<int>(obj, v) == 42, ""); }
+ static_assert(std::visit<int>(obj, v) == 42, "");
}
{
using V = std::variant<short, long, char>;
- constexpr V v(42L);
-
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert(v.visit<int>(obj) == 42); }
-#endif
- // non-member
- { static_assert(std::visit<int>(obj, v) == 42, ""); }
+ 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 V2 = std::variant<int, char *, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
constexpr V3 v3;
-
- // non-member
- { static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); }
+ 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>;
+ 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;
-
- // non-member
- { static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); }
+ 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);
-
- // non-member
- { static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); }
+ 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);
-
- // non-member
- { 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, "");
}
}
@@ -552,86 +320,60 @@ template <typename ReturnType>
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
-
-# if _LIBCPP_STD_VER >= 26
- // member
- auto test_member = [&](auto&& v) {
- try {
- v.template visit<ReturnType>(obj);
- } catch (const std::bad_variant_access&) {
- return true;
- } catch (...) {
- }
- return false;
- };
-# endif
- // non-member
- auto test_nonmember = [&](auto&&... args) {
+ auto test = [&](auto &&... args) {
try {
std::visit<ReturnType>(obj, args...);
- } catch (const std::bad_variant_access&) {
+ } catch (const std::bad_variant_access &) {
return true;
} catch (...) {
}
return false;
};
-
{
using V = std::variant<int, MakeEmptyT>;
V v;
-# if _LIBCPP_STD_VER >= 26
- makeEmpty(v);
-
- assert(test_member(v));
-# endif
makeEmpty(v);
-
- assert(test_nonmember(v));
+ assert(test(v));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*>;
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void *>;
V v;
makeEmpty(v);
V2 v2("hello");
-
- assert(test_nonmember(v, v2));
+ assert(test(v, v2));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*>;
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void *>;
V v;
makeEmpty(v);
V2 v2("hello");
-
- assert(test_nonmember(v2, v));
+ assert(test(v2, v));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*, MakeEmptyT>;
+ 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_nonmember(v, v2));
+ assert(test(v, v2));
}
{
using V = std::variant<int, long, double, MakeEmptyT>;
- V v1(42L), v2(101), v3(202), v4(1.1);
+ V v1(42l), v2(101), v3(202), v4(1.1);
makeEmpty(v1);
-
- assert(test_nonmember(v1, v2, v3, v4));
+ 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);
+ V v1(42l), v2(101), v3(202), v4(1.1);
makeEmpty(v1);
makeEmpty(v2);
makeEmpty(v3);
makeEmpty(v4);
-
- assert(test_nonmember(v1, v2, v3, v4));
+ assert(test(v1, v2, v3, v4));
}
#endif
}
@@ -642,35 +384,20 @@ void test_caller_accepts_nonconst() {
struct A {};
struct Visitor {
auto operator()(A&) {
- if constexpr (!std::is_void_v<ReturnType>) {
+ if constexpr (!std::is_void_v<ReturnType>)
+ {
return ReturnType{};
}
}
};
std::variant<A> v;
-
-#if _LIBCPP_STD_VER >= 26
- // member
- { v.template visit<ReturnType>(Visitor{}); }
-#endif
- // non-member
- { std::visit<ReturnType>(Visitor{}, v); }
+ std::visit<ReturnType>(Visitor{}, v);
}
void test_constexpr_explicit_side_effect() {
auto test_lambda = [](int arg) constexpr {
std::variant<int> v = 101;
-
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.template visit<void>([arg](int& x) constexpr { x = arg; });
- }
-#endif
- // non-member
- {
- std::visit<void>([arg](int& x) constexpr { x = arg; }, v);
- }
+ std::visit<void>([arg](int& x) constexpr { x = arg; }, v);
return std::get<int>(v);
};
@@ -680,34 +407,18 @@ void test_constexpr_explicit_side_effect() {
void test_derived_from_variant() {
struct MyVariant : std::variant<short, long, float> {};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- MyVariant{42}.template visit<bool>([](auto x) {
- assert(x == 42);
- return true;
- });
- MyVariant{-1.3f}.template visit<bool>([](auto x) {
- assert(x == -1.3f);
- return true;
- });
- }
-#endif
- // non-member
- {
- std::visit<bool>(
- [](auto x) {
- assert(x == 42);
- return true;
- },
- MyVariant{42});
- std::visit<bool>(
- [](auto x) {
- assert(x == -1.3f);
- return true;
- },
- MyVariant{-1.3f});
- }
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 42);
+ return true;
+ },
+ MyVariant{42});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == -1.3f);
+ return true;
+ },
+ MyVariant{-1.3f});
// Check that visit does not take index nor valueless_by_exception members from the base class.
struct EvilVariantBase {
@@ -715,46 +426,29 @@ void test_derived_from_variant() {
char valueless_by_exception;
};
- struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
+ struct EvilVariant1 : std::variant<int, long, double>,
+ std::tuple<int>,
+ EvilVariantBase {
using std::variant<int, long, double>::variant;
};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- EvilVariant1{12}.template visit<bool>([](auto x) {
- assert(x == 12);
- return true;
- });
- EvilVariant1{12.3}.template visit<bool>([](auto x) {
- assert(x == 12.3);
- return true;
- });
- }
-#endif
- // non-member
- {
- std::visit<bool>(
- [](auto x) {
- assert(x == 12);
- return true;
- },
- EvilVariant1{12});
- std::visit<bool>(
- [](auto x) {
- assert(x == 12.3);
- return true;
- },
- EvilVariant1{12.3});
- }
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12);
+ return true;
+ },
+ EvilVariant1{12});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12.3);
+ return true;
+ },
+ EvilVariant1{12.3});
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
struct Callable {
- bool operator()() const {
- assert(false);
- return false;
- }
+ bool operator()() const { assert(false); return false; }
};
Callable __impl;
@@ -764,34 +458,18 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- EvilVariant2{12}.template visit<bool>([](auto x) {
- assert(x == 12);
- return true;
- });
- EvilVariant2{12.3}.template visit<bool>([](auto x) {
- assert(x == 12.3);
- return true;
- });
- }
-#endif
- // non-member
- {
- std::visit<bool>(
- [](auto x) {
- assert(x == 12);
- return true;
- },
- EvilVariant2{12});
- std::visit<bool>(
- [](auto x) {
- assert(x == 12.3);
- return true;
- },
- EvilVariant2{12.3});
- }
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12);
+ return true;
+ },
+ EvilVariant2{12});
+ std::visit<bool>(
+ [](auto x) {
+ assert(x == 12.3);
+ return true;
+ },
+ EvilVariant2{12.3});
}
struct any_visitor {
@@ -801,7 +479,8 @@ struct any_visitor {
}
};
-template <typename T, typename = decltype(std::visit<bool>(std::declval<any_visitor&>(), std::declval<T>()))>
+template <typename T, typename = decltype(std::visit<bool>(
+ std::declval<any_visitor&>(), std::declval<T>()))>
constexpr bool has_visit(int) {
return true;
}
@@ -819,7 +498,6 @@ void test_sfinae() {
}
int main(int, char**) {
- test_overload_ambiguity();
test_call_operator_forwarding<void>();
test_argument_forwarding<void>();
test_return_type<void>();
>From 4d3ff8bd92f92404db1d1dd56e8ff4a5b5226dbb Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 08:25:02 +0200
Subject: [PATCH 13/28] Renamed files and cleanup
---
.../variant.visit/member.visit.pass.cpp | 6 ++---
.../member.visit.robust_against_adl.pass.cpp | 27 ++++---------------
.../member.visit_return_type.pass.cpp | 6 ++---
...pe.pass.cpp => visit.return_type.pass.cpp} | 0
....cpp => visit.robust_against_adl.pass.cpp} | 0
5 files changed, 9 insertions(+), 30 deletions(-)
rename libcxx/test/std/utilities/variant/variant.visit/{visit_return_type.pass.cpp => visit.return_type.pass.cpp} (100%)
rename libcxx/test/std/utilities/variant/variant.visit/{robust_against_adl.pass.cpp => visit.robust_against_adl.pass.cpp} (100%)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
index 8781174ff7d669..e6e9e5fe64e4bd 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
@@ -6,17 +6,15 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// <variant>
// class variant;
+
// template<class Self, class Visitor>
// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
-// template <class Visitor, class... Variants>
-// constexpr see below visit(Visitor&& vis, Variants&&... vars);
-
#include <cassert>
#include <memory>
#include <string>
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp
index 3bd305a7c62c17..3c59d5a4c0e063 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// <variant>
@@ -16,9 +16,6 @@
// template<class R, class Self, class Visitor>
// constexpr R visit(this Self&&, Visitor&&); // since C++26
-// template <class Visitor, class... Variants>
-// constexpr see below visit(Visitor&& vis, Variants&&... vars);
-
#include <variant>
#include "test_macros.h"
@@ -33,24 +30,10 @@ constexpr bool test(bool do_it) {
if (do_it) {
std::variant<Holder<Incomplete>*, int> v = nullptr;
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit([](auto) {});
- v.visit([](auto) -> Holder<Incomplete>* { return nullptr; });
- v.visit<void>([](auto) {});
- v.visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; });
- }
-#endif
- // non-member
- {
- 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
- }
+ v.visit([](auto) {});
+ v.visit([](auto) -> Holder<Incomplete>* { return nullptr; });
+ v.visit<void>([](auto) {});
+ v.visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; });
}
return true;
}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
index 1c73d34cacd87f..a1752c834effcc 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
@@ -6,17 +6,15 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// <variant>
// class variant;
+
// template<class R, class Self, class Visitor>
// constexpr R visit(this Self&&, Visitor&&); // since C++26
-// template <class R, class Visitor, class... Variants>
-// constexpr R visit(Visitor&& vis, Variants&&... vars);
-
#include <cassert>
#include <memory>
#include <string>
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
rename to libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp
diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
rename to libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp
>From 78f5d3e8f0d7a40d0bca00fad09d93953232d0d9 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 09:02:40 +0200
Subject: [PATCH 14/28] Fixed: member.visit_return_type.pass.cpp
---
.../member.visit_return_type.pass.cpp | 645 +++---------------
1 file changed, 81 insertions(+), 564 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
index a1752c834effcc..6ff469290e44a5 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
@@ -31,12 +31,10 @@ struct overloaded : Ts... {
};
void test_overload_ambiguity() {
-#if _LIBCPP_STD_VER >= 26
using V = std::variant<float, long, std::string>;
using namespace std::string_literals;
V v{"baba"s};
- // member
v.visit(
overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }});
assert(std::get<std::string>(v) == "baba"s);
@@ -52,7 +50,6 @@ void test_overload_ambiguity() {
return x + " zmt"s;
}});
assert(std::get<std::string>(v) == "baba zmt"s);
-#endif
}
template <typename ReturnType>
@@ -78,109 +75,27 @@ void test_call_operator_forwarding() {
using V = std::variant<int>;
V v(42);
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
- v.visit<ReturnType>(cobj);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
- v.visit<ReturnType>(std::move(obj));
- assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
- v.visit<ReturnType>(std::move(cobj));
- assert(Fn::check_call<int&>(CT_Const | CT_RValue));
- }
-#endif
- // non-member
- {
- 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));
- }
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ v.visit<ReturnType>(cobj);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ v.visit<ReturnType>(std::move(obj));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ v.visit<ReturnType>(std::move(cobj));
+ 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);
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
- v.visit<ReturnType>(cobj);
- assert(Fn::check_call<long&>(CT_Const | CT_LValue));
- v.visit<ReturnType>(std::move(obj));
- assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
- v.visit<ReturnType>(std::move(cobj));
- assert(Fn::check_call<long&>(CT_Const | CT_RValue));
- }
-#endif
- // non-member
- {
- 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");
-
- // non-member
- {
- 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);
-
- // non-member
- {
- 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);
-
- // non-member
- {
- 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)));
- }
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+ v.visit<ReturnType>(cobj);
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ v.visit<ReturnType>(std::move(obj));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+ v.visit<ReturnType>(std::move(cobj));
+ assert(Fn::check_call<long&>(CT_Const | CT_RValue));
}
}
@@ -195,30 +110,14 @@ void test_argument_forwarding() {
V v(42);
const V& cv = v;
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit<ReturnType>(obj);
- assert(Fn::check_call<const int&>(val));
- std::move(v).visit<ReturnType>(obj);
- assert(Fn::check_call<int&&>(val));
- std::move(cv).visit<ReturnType>(obj);
- assert(Fn::check_call<const int&&>(val));
- }
-#endif
- // non-member
- {
- 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));
- }
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<const int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ assert(Fn::check_call<const int&&>(val));
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{ // single argument - lvalue reference
@@ -227,30 +126,14 @@ void test_argument_forwarding() {
V v(x);
const V& cv = v;
-# if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- std::move(v).visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- std::move(cv).visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- }
-# endif
- // non-member
- {
- 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));
- }
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
}
{ // single argument - rvalue reference
using V = std::variant<int&&>;
@@ -258,68 +141,16 @@ void test_argument_forwarding() {
V v(std::move(x));
const V& cv = v;
-# if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit<ReturnType>(obj);
- assert(Fn::check_call<int&>(val));
- std::move(v).visit<ReturnType>(obj);
- assert(Fn::check_call<int&&>(val));
- std::move(cv).visit<ReturnType>(obj);
- assert(Fn::check_call<int&&>(val));
- }
-# endif
- // non-member
- {
- 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));
- }
+ v.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit<ReturnType>(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit<ReturnType>(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit<ReturnType>(obj);
+ 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);
-
- // non-member
- {
- 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);
-
- // non-member
- {
- 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);
-
- // non-member
- {
- 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>
@@ -341,208 +172,53 @@ void test_return_type() {
using V = std::variant<int>;
V v(42);
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
- }
-#endif
- // non-member
- {
- 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>);
- }
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
V v(42L);
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
- static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
- }
-#endif
- // non-member
- {
- 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");
-
- // non-member
- {
- 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);
-
- // non-member
- {
- 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);
-
- // non-member
- {
- 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>);
- }
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
+ static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
}
}
void test_constexpr_void() {
constexpr ReturnFirst obj{};
- constexpr ReturnArity aobj{};
+
{
using V = std::variant<int>;
constexpr V v(42);
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert((v.visit<void>(obj), 42) == 42); }
-#endif
- // non-member
- { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
+ static_assert((v.visit<void>(obj), 42) == 42);
}
{
using V = std::variant<short, long, char>;
constexpr V v(42L);
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert((v.visit<void>(obj), 42) == 42); }
-#endif
- // non-member
- { 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;
-
- // non-member
- { 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;
-
- // non-member
- { 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);
-
- // non-member
- { 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);
-
- // non-member
- { static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); }
+ static_assert((v.visit<void>(obj), 42) == 42);
}
}
void test_constexpr_int() {
constexpr ReturnFirst obj{};
- constexpr ReturnArity aobj{};
{
using V = std::variant<int>;
constexpr V v(42);
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert(v.visit<int>(obj) == 42); }
-#endif
- // non-member
- { static_assert(std::visit<int>(obj, v) == 42, ""); }
+ static_assert(v.visit<int>(obj) == 42);
}
{
using V = std::variant<short, long, char>;
constexpr V v(42L);
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert(v.visit<int>(obj) == 42); }
-#endif
- // non-member
- { 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;
-
- // non-member
- { 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;
-
- // non-member
- { 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);
-
- // non-member
- { 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);
-
- // non-member
- { static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); }
+ static_assert(v.visit<int>(obj) == 42);
}
}
@@ -551,9 +227,7 @@ void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
-# if _LIBCPP_STD_VER >= 26
- // member
- auto test_member = [&](auto&& v) {
+ auto test = [&](auto&& v) {
try {
v.template visit<ReturnType>(obj);
} catch (const std::bad_variant_access&) {
@@ -562,74 +236,13 @@ void test_exceptions() {
}
return false;
};
-# endif
- // non-member
- auto test_nonmember = [&](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;
-# if _LIBCPP_STD_VER >= 26
makeEmpty(v);
- assert(test_member(v));
-# endif
- makeEmpty(v);
-
- assert(test_nonmember(v));
- }
- {
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*>;
- V v;
- makeEmpty(v);
- V2 v2("hello");
-
- assert(test_nonmember(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_nonmember(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_nonmember(v, v2));
- }
- {
- using V = std::variant<int, long, double, MakeEmptyT>;
- V v1(42L), v2(101), v3(202), v4(1.1);
- makeEmpty(v1);
-
- assert(test_nonmember(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_nonmember(v1, v2, v3, v4));
+ assert(test(v));
}
#endif
}
@@ -647,65 +260,34 @@ void test_caller_accepts_nonconst() {
};
std::variant<A> v;
-#if _LIBCPP_STD_VER >= 26
- // member
- { v.template visit<ReturnType>(Visitor{}); }
-#endif
- // non-member
- { std::visit<ReturnType>(Visitor{}, v); }
+ v.template visit<ReturnType>(Visitor{});
}
void test_constexpr_explicit_side_effect() {
auto test_lambda = [](int arg) constexpr {
std::variant<int> v = 101;
-#if _LIBCPP_STD_VER >= 26
- // member
{
v.template visit<void>([arg](int& x) constexpr { x = arg; });
}
-#endif
- // non-member
- {
- std::visit<void>([arg](int& x) constexpr { x = arg; }, v);
- }
+
return std::get<int>(v);
};
- static_assert(test_lambda(202) == 202, "");
+ static_assert(test_lambda(202) == 202);
}
void test_derived_from_variant() {
struct MyVariant : std::variant<short, long, float> {};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- MyVariant{42}.template visit<bool>([](auto x) {
- assert(x == 42);
- return true;
- });
- MyVariant{-1.3f}.template visit<bool>([](auto x) {
- assert(x == -1.3f);
- return true;
- });
- }
-#endif
- // non-member
- {
- std::visit<bool>(
- [](auto x) {
- assert(x == 42);
- return true;
- },
- MyVariant{42});
- std::visit<bool>(
- [](auto x) {
- assert(x == -1.3f);
- return true;
- },
- MyVariant{-1.3f});
- }
+ MyVariant{42}.template visit<bool>([](auto x) {
+ assert(x == 42);
+ return true;
+ });
+ MyVariant{-1.3f}.template visit<bool>([](auto x) {
+ assert(x == -1.3f);
+ return true;
+ });
// Check that visit does not take index nor valueless_by_exception members from the base class.
struct EvilVariantBase {
@@ -717,34 +299,14 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- EvilVariant1{12}.template visit<bool>([](auto x) {
- assert(x == 12);
- return true;
- });
- EvilVariant1{12.3}.template visit<bool>([](auto x) {
- assert(x == 12.3);
- return true;
- });
- }
-#endif
- // non-member
- {
- std::visit<bool>(
- [](auto x) {
- assert(x == 12);
- return true;
- },
- EvilVariant1{12});
- std::visit<bool>(
- [](auto x) {
- assert(x == 12.3);
- return true;
- },
- EvilVariant1{12.3});
- }
+ EvilVariant1{12}.template visit<bool>([](auto x) {
+ assert(x == 12);
+ return true;
+ });
+ EvilVariant1{12.3}.template visit<bool>([](auto x) {
+ assert(x == 12.3);
+ return true;
+ });
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
@@ -762,58 +324,14 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- EvilVariant2{12}.template visit<bool>([](auto x) {
- assert(x == 12);
- return true;
- });
- EvilVariant2{12.3}.template visit<bool>([](auto x) {
- assert(x == 12.3);
- return true;
- });
- }
-#endif
- // non-member
- {
- std::visit<bool>(
- [](auto x) {
- assert(x == 12);
- return true;
- },
- EvilVariant2{12});
- std::visit<bool>(
- [](auto x) {
- assert(x == 12.3);
- return true;
- },
- EvilVariant2{12.3});
- }
-}
-
-struct any_visitor {
- template <typename T>
- bool operator()(const T&) {
+ EvilVariant2{12}.template visit<bool>([](auto x) {
+ assert(x == 12);
return true;
- }
-};
-
-template <typename T, typename = decltype(std::visit<bool>(std::declval<any_visitor&>(), std::declval<T>()))>
-constexpr bool has_visit(int) {
- return true;
-}
-
-template <typename T>
-constexpr bool has_visit(...) {
- return false;
-}
-
-void test_sfinae() {
- struct BadVariant : std::variant<short>, std::variant<long, float> {};
-
- static_assert(has_visit<std::variant<int> >(int()));
- static_assert(!has_visit<BadVariant>(int()));
+ });
+ EvilVariant2{12.3}.template visit<bool>([](auto x) {
+ assert(x == 12.3);
+ return true;
+ });
}
int main(int, char**) {
@@ -832,7 +350,6 @@ int main(int, char**) {
test_caller_accepts_nonconst<int>();
test_constexpr_explicit_side_effect();
test_derived_from_variant();
- test_sfinae();
return 0;
}
>From 1bcbb51d5d7b680fb622a3e09c733297c685bc94 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 09:11:28 +0200
Subject: [PATCH 15/28] Fixed: member.visit.pass.cpp
---
.../variant.visit/member.visit.pass.cpp | 541 ++----------------
1 file changed, 63 insertions(+), 478 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
index e6e9e5fe64e4bd..3269cd412f2a26 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
@@ -47,109 +47,27 @@ void test_call_operator_forwarding() {
using V = std::variant<int>;
V v(42);
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
- v.visit(cobj);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
- v.visit(std::move(obj));
- assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
- v.visit(std::move(cobj));
- assert(Fn::check_call<int&>(CT_Const | CT_RValue));
- }
-#endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
- std::visit(cobj, v);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
- std::visit(std::move(obj), v);
- assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
- std::visit(std::move(cobj), v);
- assert(Fn::check_call<int&>(CT_Const | CT_RValue));
- }
+ v.visit(obj);
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ v.visit(cobj);
+ assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ v.visit(std::move(obj));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+ v.visit(std::move(cobj));
+ 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);
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
- v.visit(cobj);
- assert(Fn::check_call<long&>(CT_Const | CT_LValue));
- v.visit(std::move(obj));
- assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
- v.visit(std::move(cobj));
- assert(Fn::check_call<long&>(CT_Const | CT_RValue));
- }
-#endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
- std::visit(cobj, v);
- assert(Fn::check_call<long&>(CT_Const | CT_LValue));
- std::visit(std::move(obj), v);
- assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
- std::visit(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");
-
- // non-member
- {
- std::visit(obj, v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v, v2);
- assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
- std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
- std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
- std::visit(cobj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
- std::visit(std::move(obj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
- std::visit(std::move(cobj), v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
- }
+ v.visit(obj);
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+ v.visit(cobj);
+ assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ v.visit(std::move(obj));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+ v.visit(std::move(cobj));
+ assert(Fn::check_call<long&>(CT_Const | CT_RValue));
}
}
@@ -164,30 +82,14 @@ void test_argument_forwarding() {
V v(42);
const V& cv = v;
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit(obj);
- assert(Fn::check_call<const int&>(val));
- std::move(v).visit(obj);
- assert(Fn::check_call<int&&>(val));
- std::move(cv).visit(obj);
- assert(Fn::check_call<const int&&>(val));
- }
-#endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, cv);
- assert(Fn::check_call<const int&>(val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&&>(val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<const int&&>(val));
- }
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit(obj);
+ assert(Fn::check_call<const int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit(obj);
+ assert(Fn::check_call<const int&&>(val));
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{ // single argument - lvalue reference
@@ -196,31 +98,15 @@ void test_argument_forwarding() {
V v(x);
const V& cv = v;
-# if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<int&>(val));
- cv.visit(obj);
- assert(Fn::check_call<int&>(val));
- std::move(v).visit(obj);
- assert(Fn::check_call<int&>(val));
- std::move(cv).visit(obj);
- assert(Fn::check_call<int&>(val));
- assert(false);
- }
-# endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, cv);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&>(val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<int&>(val));
- }
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cv.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(cv).visit(obj);
+ assert(Fn::check_call<int&>(val));
+ assert(false);
}
{ // single argument - rvalue reference
using V = std::variant<int&&>;
@@ -228,68 +114,16 @@ void test_argument_forwarding() {
V v(std::move(x));
const V& cv = v;
-# if _LIBCPP_STD_VER >= 26
- // member
- {
- v.visit(obj);
- assert(Fn::check_call<int&>(val));
- cvstd::visit(obj);
- assert(Fn::check_call<int&>(val));
- std::move(v).visit(obj);
- assert(Fn::check_call<int&&>(val));
- std::move(cv).visit(obj);
- assert(Fn::check_call<int&&>(val));
- }
-# endif
- // non-member
- {
- std::visit(obj, v);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, cv);
- assert(Fn::check_call<int&>(val));
- std::visit(obj, std::move(v));
- assert(Fn::check_call<int&&>(val));
- std::visit(obj, std::move(cv));
- assert(Fn::check_call<int&&>(val));
- }
+ v.visit(obj);
+ assert(Fn::check_call<int&>(val));
+ cvstd::visit(obj);
+ assert(Fn::check_call<int&>(val));
+ std::move(v).visit(obj);
+ assert(Fn::check_call<int&&>(val));
+ std::move(cv).visit(obj);
+ 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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3);
- assert((Fn::check_call<int&, std::string&, long&>(val)));
- std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int&, double&>(val)));
- std::visit(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);
-
- // non-member
- {
- std::visit(obj, v1, v2, v3, v4);
- assert((Fn::check_call<long&, std::string&, int*&, double&>(val)));
- std::visit(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)));
- }
- }
}
void test_return_type() {
@@ -297,158 +131,40 @@ void test_return_type() {
Fn obj{};
const Fn& cobj = obj;
- { // test call operator forwarding - no variant
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
- }
- }
{ // test call operator forwarding - single variant, single arg
using V = std::variant<int>;
V v(42);
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
- static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
- static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
- static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
- }
-#endif
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
- }
+ static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
}
{ // test call operator forwarding - single variant, multi arg
using V = std::variant<int, long, double>;
V v(42L);
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
- static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
- static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
- static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
- }
-#endif
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
- }
- }
- { // 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");
-
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
- }
- }
- {
- using V = std::variant<int, long, double, std::string>;
- V v1(42L), v2("hello"), v3(101), v4(1.1);
-
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
- }
- }
- {
- using V = std::variant<int, long, double, int*, std::string>;
- V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
-
- // non-member
- {
- static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
- static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
- }
+ static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
+ static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
}
}
void test_constexpr() {
constexpr ReturnFirst obj{};
- constexpr ReturnArity aobj{};
{
using V = std::variant<int>;
constexpr V v(42);
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert(v.visit(obj) == 42); }
-#endif
- // non-member
- { static_assert(std::visit(obj, v) == 42, ""); }
+ static_assert(v.visit(obj) == 42);
}
{
using V = std::variant<short, long, char>;
constexpr V v(42L);
-#if _LIBCPP_STD_VER >= 26
- // member
- { static_assert(v.visit(obj) == 42); }
-#endif
- // non-member
- { static_assert(std::visit(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;
-
- // non-member
- { static_assert(std::visit(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;
-
- // non-member
- { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); }
- }
- {
- using V = std::variant<int, long, double, int*>;
- constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
-
- // non-member
- { static_assert(std::visit(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);
-
- // non-member
- { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); }
+ static_assert(v.visit(obj) == 42);
}
}
@@ -456,9 +172,7 @@ void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
-# if _LIBCPP_STD_VER >= 26
- // member
- auto test_member = [&](auto&& v) {
+ auto test = [&](auto&& v) {
try {
v.visit(obj);
} catch (const std::bad_variant_access&) {
@@ -467,74 +181,13 @@ void test_exceptions() {
}
return false;
};
-# endif
- // non-member
- auto test_nonmember = [&](auto&&... args) {
- try {
- std::visit(obj, args...);
- } catch (const std::bad_variant_access&) {
- return true;
- } catch (...) {
- }
- return false;
- };
{
using V = std::variant<int, MakeEmptyT>;
V v;
-# if _LIBCPP_STD_VER >= 26
- makeEmpty(v);
-
- assert(test_member(v));
-# endif
makeEmpty(v);
- assert(test_nonmember(v));
- }
- {
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*>;
- V v;
- makeEmpty(v);
- V2 v2("hello");
-
- assert(test_nonmember(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_nonmember(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_nonmember(v, v2));
- }
- {
- using V = std::variant<int, long, double, MakeEmptyT>;
- V v1(42l), v2(101), v3(202), v4(1.1);
- makeEmpty(v1);
-
- assert(test_nonmember(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_nonmember(v1, v2, v3, v4));
+ assert(test(v));
}
#endif
}
@@ -547,12 +200,7 @@ void test_caller_accepts_nonconst() {
};
std::variant<A> v;
-#if _LIBCPP_STD_VER >= 26
- // member
- { v.visit(Visitor{}); }
-#endif
- // non-member
- { std::visit(Visitor{}, v); }
+ v.visit(Visitor{});
}
struct MyVariant : std::variant<short, long, float> {};
@@ -568,24 +216,11 @@ void test_derived_from_variant() {
auto v1 = MyVariant{42};
const auto cv1 = MyVariant{142};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- v1.visit([](auto x) { assert(x == 42); });
- cv1.visit([](auto x) { assert(x == 142); });
- MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); });
- std::move(v1).visit([](auto x) { assert(x == 42); });
- std::move(cv1).visit([](auto x) { assert(x == 142); });
- }
-#endif
- // non-member
- {
- std::visit([](auto x) { assert(x == 42); }, v1);
- std::visit([](auto x) { assert(x == 142); }, cv1);
- std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});
- std::visit([](auto x) { assert(x == 42); }, std::move(v1));
- std::visit([](auto x) { assert(x == 142); }, std::move(cv1));
- }
+ v1.visit([](auto x) { assert(x == 42); });
+ cv1.visit([](auto x) { assert(x == 142); });
+ MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); });
+ std::move(v1).visit([](auto x) { assert(x == 42); });
+ std::move(cv1).visit([](auto x) { assert(x == 142); });
// Check that visit does not take index nor valueless_by_exception members from the base class.
struct EvilVariantBase {
@@ -597,18 +232,8 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- EvilVariant1{12}.visit([](auto x) { assert(x == 12); });
- EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); });
- }
-#endif
- // non-member
- {
- std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
- std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});
- }
+ EvilVariant1{12}.visit([](auto x) { assert(x == 12); });
+ EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); });
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
@@ -626,47 +251,8 @@ void test_derived_from_variant() {
using std::variant<int, long, double>::variant;
};
-#if _LIBCPP_STD_VER >= 26
- // member
- {
- EvilVariant2{12}.visit([](auto x) { assert(x == 12); });
- EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); });
- }
-#endif
- // non-member
- {
- std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
- std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});
- }
-}
-
-struct any_visitor {
- template <typename T>
- void operator()(const T&) const {}
-};
-
-template <typename T, typename = decltype(std::visit(std::declval<any_visitor&>(), std::declval<T>()))>
-constexpr bool has_visit(int) {
- return true;
-}
-
-template <typename T>
-constexpr bool has_visit(...) {
- return false;
-}
-
-void test_sfinae() {
- struct BadVariant : std::variant<short>, std::variant<long, float> {};
- struct BadVariant2 : private std::variant<long, float> {};
- struct GoodVariant : std::variant<long, float> {};
- struct GoodVariant2 : GoodVariant {};
-
- static_assert(!has_visit<int>(0));
- static_assert(!has_visit<BadVariant>(0));
- static_assert(!has_visit<BadVariant2>(0));
- static_assert(has_visit<std::variant<int>>(0));
- static_assert(has_visit<GoodVariant>(0));
- static_assert(has_visit<GoodVariant2>(0));
+ EvilVariant2{12}.visit([](auto x) { assert(x == 12); });
+ EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); });
}
int main(int, char**) {
@@ -677,7 +263,6 @@ int main(int, char**) {
test_exceptions();
test_caller_accepts_nonconst();
test_derived_from_variant();
- test_sfinae();
return 0;
}
>From 5df0feaf854c9f24282ae87a8ee9e30017819234 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 09:23:28 +0200
Subject: [PATCH 16/28] Formatted: visit.return_type.pass.cpp and
visit.robust_against_adl.pass.cpp
---
.../variant.visit/visit.return_type.pass.cpp | 153 +++++++++---------
.../visit.robust_against_adl.pass.cpp | 33 ++--
2 files changed, 93 insertions(+), 93 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp
index eb425c07f93222..246b01a68f6aa9 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp
@@ -26,7 +26,7 @@ template <typename ReturnType>
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn &cobj = obj;
+ const Fn& cobj = obj;
{ // test call operator forwarding - no variant
std::visit<ReturnType>(obj);
assert(Fn::check_call<>(CT_NonConst | CT_LValue));
@@ -41,63 +41,63 @@ void test_call_operator_forwarding() {
using V = std::variant<int>;
V v(42);
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
+ assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
std::visit<ReturnType>(cobj, v);
- assert(Fn::check_call<int &>(CT_Const | CT_LValue));
+ 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));
+ 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));
+ 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));
+ assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
std::visit<ReturnType>(cobj, v);
- assert(Fn::check_call<long &>(CT_Const | CT_LValue));
+ 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));
+ 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));
+ 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>;
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
}
}
@@ -109,69 +109,69 @@ void test_argument_forwarding() {
{ // single argument - value type
using V = std::variant<int>;
V v(42);
- const V &cv = v;
+ const V& cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<const int &>(Val));
+ assert(Fn::check_call<const int&>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int &&>(Val));
+ assert(Fn::check_call<int&&>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<const int &&>(Val));
+ 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;
+ using V = std::variant<int&>;
+ int x = 42;
V v(x);
- const V &cv = v;
+ const V& cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
}
{ // single argument - rvalue reference
- using V = std::variant<int &&>;
- int x = 42;
+ using V = std::variant<int&&>;
+ int x = 42;
V v(std::move(x));
- const V &cv = v;
+ const V& cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<int &>(Val));
+ assert(Fn::check_call<int&>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int &&>(Val));
+ assert(Fn::check_call<int&&>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<int &&>(Val));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(Val)));
}
}
@@ -179,7 +179,7 @@ template <typename ReturnType>
void test_return_type() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn &cobj = 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>);
@@ -203,8 +203,8 @@ void test_return_type() {
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>;
+ 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>);
@@ -245,7 +245,7 @@ void test_constexpr_void() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
+ using V2 = std::variant<int, char*, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
@@ -254,20 +254,20 @@ void test_constexpr_void() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
- using V3 = std::variant<void *, int, 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 *>;
+ 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 *>;
+ 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, "");
}
@@ -288,7 +288,7 @@ void test_constexpr_int() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
+ using V2 = std::variant<int, char*, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
@@ -297,20 +297,20 @@ void test_constexpr_int() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char *, long long>;
- using V3 = std::variant<void *, int, 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 *>;
+ 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 *>;
+ 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, "");
}
@@ -320,10 +320,10 @@ template <typename ReturnType>
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
- auto test = [&](auto &&... args) {
+ auto test = [&](auto&&... args) {
try {
std::visit<ReturnType>(obj, args...);
- } catch (const std::bad_variant_access &) {
+ } catch (const std::bad_variant_access&) {
return true;
} catch (...) {
}
@@ -336,24 +336,24 @@ void test_exceptions() {
assert(test(v));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void *>;
+ 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 *>;
+ 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>;
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void*, MakeEmptyT>;
V v;
makeEmpty(v);
V2 v2;
@@ -384,8 +384,7 @@ void test_caller_accepts_nonconst() {
struct A {};
struct Visitor {
auto operator()(A&) {
- if constexpr (!std::is_void_v<ReturnType>)
- {
+ if constexpr (!std::is_void_v<ReturnType>) {
return ReturnType{};
}
}
@@ -426,9 +425,7 @@ void test_derived_from_variant() {
char valueless_by_exception;
};
- struct EvilVariant1 : std::variant<int, long, double>,
- std::tuple<int>,
- EvilVariantBase {
+ struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
using std::variant<int, long, double>::variant;
};
@@ -448,7 +445,10 @@ void test_derived_from_variant() {
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
struct Callable {
- bool operator()() const { assert(false); return false; }
+ bool operator()() const {
+ assert(false);
+ return false;
+ }
};
Callable __impl;
@@ -479,8 +479,7 @@ struct any_visitor {
}
};
-template <typename T, typename = decltype(std::visit<bool>(
- std::declval<any_visitor&>(), std::declval<T>()))>
+template <typename T, typename = decltype(std::visit<bool>(std::declval<any_visitor&>(), std::declval<T>()))>
constexpr bool has_visit(int) {
return true;
}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp
index 6f17fa32648d41..125ac20490d6a9 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp
@@ -17,27 +17,28 @@
#include "test_macros.h"
struct Incomplete;
-template<class T> struct Holder { T t; };
+template <class T>
+struct Holder {
+ T t;
+};
-constexpr bool test(bool do_it)
-{
- if (do_it) {
- std::variant<Holder<Incomplete>*, int> v = nullptr;
- std::visit([](auto){}, v);
- std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
+constexpr bool test(bool do_it) {
+ if (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);
+ std::visit<void>([](auto) {}, v);
+ std::visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
#endif
- }
- return true;
+ }
+ return true;
}
-int main(int, char**)
-{
- test(true);
+int main(int, char**) {
+ test(true);
#if TEST_STD_VER > 17
- static_assert(test(true));
+ static_assert(test(true));
#endif
- return 0;
+ return 0;
}
>From 8eaaa410716356ceb5ff876dfb58257148d6fb56 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 10:20:12 +0200
Subject: [PATCH 17/28] Addressed comments
---
libcxx/docs/Status/Cxx2c.rst | 2 -
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
...l.pass.cpp => robust_against_adl.pass.cpp} | 33 ++--
...pe.pass.cpp => visit_return_type.pass.cpp} | 153 +++++++++---------
4 files changed, 94 insertions(+), 96 deletions(-)
rename libcxx/test/std/utilities/variant/variant.visit/{visit.robust_against_adl.pass.cpp => robust_against_adl.pass.cpp} (57%)
rename libcxx/test/std/utilities/variant/variant.visit/{visit.return_type.pass.cpp => visit_return_type.pass.cpp} (76%)
diff --git a/libcxx/docs/Status/Cxx2c.rst b/libcxx/docs/Status/Cxx2c.rst
index 5c700d2cb0d6d3..a7ebc4662f517c 100644
--- a/libcxx/docs/Status/Cxx2c.rst
+++ b/libcxx/docs/Status/Cxx2c.rst
@@ -40,8 +40,6 @@ Paper Status
.. note::
.. [#note-P2510R3] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
- .. [#note-P2637R3] P2637R3: Implemented `variant` member `visit`
-
.. _issues-status-cxx2c:
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index a3214ab2bfe75c..380686ceb8305b 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -17,7 +17,7 @@
"`P0792R14 <https://wg21.link/P0792R14>`__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","",""
"`P2874R2 <https://wg21.link/P2874R2>`__","LWG","Mandating Annex D Require No More","Varna June 2023","","",""
"`P2757R3 <https://wg21.link/P2757R3>`__","LWG","Type-checking format args","Varna June 2023","","","|format|"
-"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","|Partial| [#note-P2637R3]","18.0",""
+"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","|Partial|","18.0",""
"`P2641R4 <https://wg21.link/P2641R4>`__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","",""
"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","","",""
"`P2697R1 <https://wg21.link/P2697R1>`__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0",""
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
similarity index 57%
rename from libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp
rename to libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
index 125ac20490d6a9..6f17fa32648d41 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp
@@ -17,28 +17,27 @@
#include "test_macros.h"
struct Incomplete;
-template <class T>
-struct Holder {
- T t;
-};
+template<class T> struct Holder { T t; };
-constexpr bool test(bool do_it) {
- if (do_it) {
- std::variant<Holder<Incomplete>*, int> v = nullptr;
- std::visit([](auto) {}, v);
- std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
+constexpr bool test(bool do_it)
+{
+ if (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);
+ std::visit<void>([](auto){}, v);
+ std::visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
#endif
- }
- return true;
+ }
+ return true;
}
-int main(int, char**) {
- test(true);
+int main(int, char**)
+{
+ test(true);
#if TEST_STD_VER > 17
- static_assert(test(true));
+ static_assert(test(true));
#endif
- return 0;
+ return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
similarity index 76%
rename from libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp
rename to libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
index 246b01a68f6aa9..eb425c07f93222 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp
@@ -26,7 +26,7 @@ template <typename ReturnType>
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn& cobj = obj;
+ const Fn &cobj = obj;
{ // test call operator forwarding - no variant
std::visit<ReturnType>(obj);
assert(Fn::check_call<>(CT_NonConst | CT_LValue));
@@ -41,63 +41,63 @@ void test_call_operator_forwarding() {
using V = std::variant<int>;
V v(42);
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+ assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
std::visit<ReturnType>(cobj, v);
- assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+ 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));
+ 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));
+ 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));
+ assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
std::visit<ReturnType>(cobj, v);
- assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+ 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));
+ 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));
+ 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>;
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));
}
}
@@ -109,69 +109,69 @@ void test_argument_forwarding() {
{ // single argument - value type
using V = std::variant<int>;
V v(42);
- const V& cv = v;
+ const V &cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int &>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<const int&>(Val));
+ assert(Fn::check_call<const int &>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int&&>(Val));
+ assert(Fn::check_call<int &&>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<const int&&>(Val));
+ 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;
+ using V = std::variant<int &>;
+ int x = 42;
V v(x);
- const V& cv = v;
+ const V &cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int &>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int &>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int &>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int &>(Val));
}
{ // single argument - rvalue reference
- using V = std::variant<int&&>;
- int x = 42;
+ using V = std::variant<int &&>;
+ int x = 42;
V v(std::move(x));
- const V& cv = v;
+ const V &cv = v;
std::visit<ReturnType>(obj, v);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int &>(Val));
std::visit<ReturnType>(obj, cv);
- assert(Fn::check_call<int&>(Val));
+ assert(Fn::check_call<int &>(Val));
std::visit<ReturnType>(obj, std::move(v));
- assert(Fn::check_call<int&&>(Val));
+ assert(Fn::check_call<int &&>(Val));
std::visit<ReturnType>(obj, std::move(cv));
- assert(Fn::check_call<int&&>(Val));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ 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)));
+ assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val)));
}
}
@@ -179,7 +179,7 @@ template <typename ReturnType>
void test_return_type() {
using Fn = ForwardingCallObject;
Fn obj{};
- const Fn& cobj = 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>);
@@ -203,8 +203,8 @@ void test_return_type() {
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>;
+ 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>);
@@ -245,7 +245,7 @@ void test_constexpr_void() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char*, long long>;
+ using V2 = std::variant<int, char *, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
@@ -254,20 +254,20 @@ void test_constexpr_void() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char*, long long>;
- using V3 = std::variant<void*, int, 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*>;
+ 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*>;
+ 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, "");
}
@@ -288,7 +288,7 @@ void test_constexpr_int() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char*, long long>;
+ using V2 = std::variant<int, char *, long long>;
using V3 = std::variant<bool, int, int>;
constexpr V1 v1;
constexpr V2 v2(nullptr);
@@ -297,20 +297,20 @@ void test_constexpr_int() {
}
{
using V1 = std::variant<int>;
- using V2 = std::variant<int, char*, long long>;
- using V3 = std::variant<void*, int, 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*>;
+ 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*>;
+ 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, "");
}
@@ -320,10 +320,10 @@ template <typename ReturnType>
void test_exceptions() {
#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
- auto test = [&](auto&&... args) {
+ auto test = [&](auto &&... args) {
try {
std::visit<ReturnType>(obj, args...);
- } catch (const std::bad_variant_access&) {
+ } catch (const std::bad_variant_access &) {
return true;
} catch (...) {
}
@@ -336,24 +336,24 @@ void test_exceptions() {
assert(test(v));
}
{
- using V = std::variant<int, MakeEmptyT>;
- using V2 = std::variant<long, std::string, void*>;
+ 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*>;
+ 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>;
+ using V = std::variant<int, MakeEmptyT>;
+ using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
V v;
makeEmpty(v);
V2 v2;
@@ -384,7 +384,8 @@ void test_caller_accepts_nonconst() {
struct A {};
struct Visitor {
auto operator()(A&) {
- if constexpr (!std::is_void_v<ReturnType>) {
+ if constexpr (!std::is_void_v<ReturnType>)
+ {
return ReturnType{};
}
}
@@ -425,7 +426,9 @@ void test_derived_from_variant() {
char valueless_by_exception;
};
- struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
+ struct EvilVariant1 : std::variant<int, long, double>,
+ std::tuple<int>,
+ EvilVariantBase {
using std::variant<int, long, double>::variant;
};
@@ -445,10 +448,7 @@ void test_derived_from_variant() {
// Check that visit unambiguously picks the variant, even if the other base has __impl member.
struct ImplVariantBase {
struct Callable {
- bool operator()() const {
- assert(false);
- return false;
- }
+ bool operator()() const { assert(false); return false; }
};
Callable __impl;
@@ -479,7 +479,8 @@ struct any_visitor {
}
};
-template <typename T, typename = decltype(std::visit<bool>(std::declval<any_visitor&>(), std::declval<T>()))>
+template <typename T, typename = decltype(std::visit<bool>(
+ std::declval<any_visitor&>(), std::declval<T>()))>
constexpr bool has_visit(int) {
return true;
}
>From 38e8f433d90440a811ce0df72727b5f12921749c Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 10:30:10 +0200
Subject: [PATCH 18/28] Removed test case
---
.../variant/variant.visit/member.visit.pass.cpp | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
index 3269cd412f2a26..d140fb54afe005 100644
--- a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
@@ -30,19 +30,6 @@ void test_call_operator_forwarding() {
Fn obj{};
const Fn& cobj = obj;
- { // test call operator forwarding - no variant
- // non-member
- {
- std::visit(obj);
- assert(Fn::check_call<>(CT_NonConst | CT_LValue));
- std::visit(cobj);
- assert(Fn::check_call<>(CT_Const | CT_LValue));
- std::visit(std::move(obj));
- assert(Fn::check_call<>(CT_NonConst | CT_RValue));
- std::visit(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);
>From 6de98f30f855e5d8c3f3b2929c778bdf229081fd Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 10:40:29 +0200
Subject: [PATCH 19/28] Addressed comment
---
libcxx/include/variant | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 4c9b04942f2779..2c7e1f6a56d3f2 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -72,9 +72,9 @@ namespace std {
// [variant.visit], visitation
template<class Self, class Visitor>
- constexpr decltype(auto) visit(this Self&&, Visitor&&);
+ constexpr decltype(auto) visit(this Self&&, Visitor&&); // Since C++26
template<class R, class Self, class Visitor>
- constexpr R visit(this Self&&, Visitor&&);
+ constexpr R visit(this Self&&, Visitor&&); // Since C++26
};
// 20.7.3, variant helper classes
>From 759e0d545426b2ee3851cc33803d80661ce6bc41 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 11:03:15 +0200
Subject: [PATCH 20/28] WIP: Experiment with forward declaration
---
libcxx/include/variant | 92 +++++++++++++++++++++++++++++-------------
1 file changed, 63 insertions(+), 29 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 2c7e1f6a56d3f2..f6cc3311a09fcb 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1137,6 +1137,52 @@ using __best_match_t = typename invoke_result_t<_MakeOverloads<_Types...>, _Tp,
} // namespace __variant_detail
+# define __VISIT_FORWARD_DECL
+
+# ifdef __VISIT_FORWARD_DECL
+template < class _Visitor, class... _Vs, typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto)
+visit(_Visitor&& __visitor, _Vs&&... __vs);
+
+# if _LIBCPP_STD_VER >= 20
+template < class _Rp,
+ class _Visitor,
+ class... _Vs,
+ typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
+visit(_Visitor&& __visitor, _Vs&&... __vs);
+# endif
+# else // __VISIT_FORWARD_DECL
+template <class... _Vs>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) {
+ const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception());
+ if (__valueless) {
+ __throw_bad_variant_access();
+ }
+}
+
+template < class _Visitor, class... _Vs, typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto)
+visit(_Visitor&& __visitor, _Vs&&... __vs) {
+ using __variant_detail::__visitation::__variant;
+ std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
+ return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+}
+
+# if _LIBCPP_STD_VER >= 20
+template < class _Rp,
+ class _Visitor,
+ class... _Vs,
+ typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
+visit(_Visitor&& __visitor, _Vs&&... __vs) {
+ using __variant_detail::__visitation::__variant;
+ std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
+ return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+}
+# endif
+# endif // __VISIT_FORWARD_DECL
+
template <class... _Types>
class _LIBCPP_TEMPLATE_VIS _LIBCPP_DECLSPEC_EMPTY_BASES variant
: private __sfinae_ctor_base< __all<is_copy_constructible_v<_Types>...>::value,
@@ -1282,11 +1328,18 @@ public:
# if _LIBCPP_STD_VER >= 26
// [variant.visit], visitation
- template <int=0, class _Self, class _Visitor>
- constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);
- template <class _R, class _Self, class _Visitor>
- constexpr _R visit(this _Self&& __self, _Visitor&& __visitor);
+ template <int = 0, class _Self, class _Visitor>
+ constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
+ using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+ return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
+ }
+
+ template <class _Rp, class _Self, class _Visitor>
+ constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) {
+ using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+ return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self);
+ }
# endif
private:
@@ -1519,6 +1572,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const variant<_Types...>& __lhs,
return __variant::__visit_value_at(__lhs.index(), __convert_to_bool<greater_equal<>>{}, __lhs, __rhs);
}
+# ifdef __VISIT_FORWARD_DECL
template <class... _Vs>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) {
const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception());
@@ -1527,7 +1581,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr vo
}
}
-template < class _Visitor, class... _Vs, typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
+template < class _Visitor, class... _Vs, typename>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto)
visit(_Visitor&& __visitor, _Vs&&... __vs) {
using __variant_detail::__visitation::__variant;
@@ -1535,36 +1589,16 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) {
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
}
-# if _LIBCPP_STD_VER >= 20
-template < class _Rp,
- class _Visitor,
- class... _Vs,
- typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
+# if _LIBCPP_STD_VER >= 20
+template < class _Rp, class _Visitor, class... _Vs, typename>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
visit(_Visitor&& __visitor, _Vs&&... __vs) {
using __variant_detail::__visitation::__variant;
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
}
-# endif
-
-# if _LIBCPP_STD_VER >= 26
-// [variant.visit], visitation
-
-template <class... _Types>
-template <int, class _Self, class _Visitor>
-constexpr decltype(auto) variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) {
- using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
- return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
-}
-
-template <class... _Types>
-template <class _Rp, class _Self, class _Visitor>
-constexpr _Rp variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) {
- using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
- return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self);
-}
-# endif
+# endif
+# endif // __VISIT_FORWARD_DECL
template <class... _Types>
_LIBCPP_HIDE_FROM_ABI auto
>From 0a99bd9e9402240b9165314b7b45d4c59175c5f4 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 11:07:41 +0200
Subject: [PATCH 21/28] Used forward declaration: `std::visit`
---
libcxx/include/variant | 43 ++++--------------------------------------
1 file changed, 4 insertions(+), 39 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index f6cc3311a09fcb..c3a4bb5782cf5e 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1137,51 +1137,18 @@ using __best_match_t = typename invoke_result_t<_MakeOverloads<_Types...>, _Tp,
} // namespace __variant_detail
-# define __VISIT_FORWARD_DECL
-
-# ifdef __VISIT_FORWARD_DECL
template < class _Visitor, class... _Vs, typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto)
visit(_Visitor&& __visitor, _Vs&&... __vs);
-# if _LIBCPP_STD_VER >= 20
+# if _LIBCPP_STD_VER >= 20
template < class _Rp,
class _Visitor,
class... _Vs,
typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
visit(_Visitor&& __visitor, _Vs&&... __vs);
-# endif
-# else // __VISIT_FORWARD_DECL
-template <class... _Vs>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) {
- const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception());
- if (__valueless) {
- __throw_bad_variant_access();
- }
-}
-
-template < class _Visitor, class... _Vs, typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto)
-visit(_Visitor&& __visitor, _Vs&&... __vs) {
- using __variant_detail::__visitation::__variant;
- std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
- return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
-}
-
-# if _LIBCPP_STD_VER >= 20
-template < class _Rp,
- class _Visitor,
- class... _Vs,
- typename = void_t<decltype(std::__as_variant(std::declval<_Vs>()))...> >
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
-visit(_Visitor&& __visitor, _Vs&&... __vs) {
- using __variant_detail::__visitation::__variant;
- std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
- return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
-}
-# endif
-# endif // __VISIT_FORWARD_DECL
+# endif
template <class... _Types>
class _LIBCPP_TEMPLATE_VIS _LIBCPP_DECLSPEC_EMPTY_BASES variant
@@ -1572,7 +1539,6 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const variant<_Types...>& __lhs,
return __variant::__visit_value_at(__lhs.index(), __convert_to_bool<greater_equal<>>{}, __lhs, __rhs);
}
-# ifdef __VISIT_FORWARD_DECL
template <class... _Vs>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) {
const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception());
@@ -1589,7 +1555,7 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) {
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
}
-# if _LIBCPP_STD_VER >= 20
+# if _LIBCPP_STD_VER >= 20
template < class _Rp, class _Visitor, class... _Vs, typename>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
visit(_Visitor&& __visitor, _Vs&&... __vs) {
@@ -1597,8 +1563,7 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) {
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
}
-# endif
-# endif // __VISIT_FORWARD_DECL
+# endif
template <class... _Types>
_LIBCPP_HIDE_FROM_ABI auto
>From ed7bc128d235de430ce3130cf3abcd8d76bcee15 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 10:10:44 +0200
Subject: [PATCH 22/28] Moved member `visit` to a separate folder.
---
.../robust_against_adl.pass.cpp} | 0
.../member.visit.pass.cpp => variant.visit.member/visit.pass.cpp} | 0
.../visit_return_type.pass.cpp} | 0
3 files changed, 0 insertions(+), 0 deletions(-)
rename libcxx/test/std/utilities/variant/{variant.visit/member.visit.robust_against_adl.pass.cpp => variant.visit.member/robust_against_adl.pass.cpp} (100%)
rename libcxx/test/std/utilities/variant/{variant.visit/member.visit.pass.cpp => variant.visit.member/visit.pass.cpp} (100%)
rename libcxx/test/std/utilities/variant/{variant.visit/member.visit_return_type.pass.cpp => variant.visit.member/visit_return_type.pass.cpp} (100%)
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp
rename to libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp
rename to libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp
rename to libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
>From fde8ea9592c471834c13bca2ae05a7739c708afb Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 3 Jan 2024 14:18:17 +0200
Subject: [PATCH 23/28] Applied frederick-vs-ja's suggestion
---
libcxx/include/variant | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index c3a4bb5782cf5e..32851caec589ba 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1296,7 +1296,11 @@ public:
# if _LIBCPP_STD_VER >= 26
// [variant.visit], visitation
- template <int = 0, class _Self, class _Visitor>
+ struct __variant_visit_barrier_tag { // unnamable when using standard library modules
+ explicit __variant_visit_barrier_tag() = default;
+ };
+
+ template <__variant_visit_barrier_tag = __variant_visit_barrier_tag{}, class _Self, class _Visitor>
constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
>From 989203e4d771e7e37de427a19e04ef8404334010 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 17 Jan 2024 17:53:33 +0200
Subject: [PATCH 24/28] Try to fix CI
---
libcxx/include/variant | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 32851caec589ba..164c5decc778ba 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1297,17 +1297,17 @@ public:
// [variant.visit], visitation
struct __variant_visit_barrier_tag { // unnamable when using standard library modules
- explicit __variant_visit_barrier_tag() = default;
+ _LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default;
};
template <__variant_visit_barrier_tag = __variant_visit_barrier_tag{}, class _Self, class _Visitor>
- constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
+ _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
}
template <class _Rp, class _Self, class _Visitor>
- constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) {
+ _LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) {
using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self);
}
>From 668f3371ad36b643e509fddee3b6bb5159ebe6f6 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 17 Jan 2024 18:10:26 +0200
Subject: [PATCH 25/28] Try to fix CI
---
libcxx/include/variant | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 164c5decc778ba..aa911728c75feb 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1302,14 +1302,14 @@ public:
template <__variant_visit_barrier_tag = __variant_visit_barrier_tag{}, class _Self, class _Visitor>
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
- using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
- return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
+ using _VariantT = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+ return std::visit(std::forward<_Visitor>(__visitor), (_VariantT)__self);
}
template <class _Rp, class _Self, class _Visitor>
_LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) {
- using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
- return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self);
+ using _VariantT = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+ return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_VariantT)__self);
}
# endif
>From 06a2402830c4aa0d1f945131bebdb69be28f3950 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Thu, 18 Jan 2024 16:29:19 +0200
Subject: [PATCH 26/28] Fix CI on AIX and Arm
---
libcxx/include/variant | 4 +---
.../variant.visit.member/robust_against_adl.pass.cpp | 7 +++++--
.../variant/variant.visit.member/visit.pass.cpp | 12 ++++++++----
.../variant.visit.member/visit_return_type.pass.cpp | 4 ++++
4 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index aa911728c75feb..17a98ab3072c18 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1293,9 +1293,7 @@ public:
__impl_.__swap(__that.__impl_);
}
-# if _LIBCPP_STD_VER >= 26
- // [variant.visit], visitation
-
+# if _LIBCPP_STD_VER >= 26 && (!defined(_LIBCPP_COMPILER_CLANG_BASED) || _LIBCPP_CLANG_VER >= 1800)
struct __variant_visit_barrier_tag { // unnamable when using standard library modules
_LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default;
};
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
index 3c59d5a4c0e063..cf8dc028d9c41a 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
@@ -20,6 +20,8 @@
#include "test_macros.h"
+#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
+
struct Incomplete;
template <class T>
struct Holder {
@@ -40,8 +42,9 @@ constexpr bool test(bool do_it) {
int main(int, char**) {
test(true);
-#if TEST_STD_VER > 17
static_assert(test(true));
-#endif
+
return 0;
}
+
+#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
index d140fb54afe005..7ef55b910dcfe9 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
@@ -25,6 +25,8 @@
#include "test_macros.h"
#include "variant_test_helpers.h"
+#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
+
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
@@ -78,7 +80,7 @@ void test_argument_forwarding() {
std::move(cv).visit(obj);
assert(Fn::check_call<const int&&>(val));
}
-#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
+# if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{ // single argument - lvalue reference
using V = std::variant<int&>;
int x = 42;
@@ -110,7 +112,7 @@ void test_argument_forwarding() {
std::move(cv).visit(obj);
assert(Fn::check_call<int&&>(val));
}
-#endif
+# endif
}
void test_return_type() {
@@ -156,7 +158,7 @@ void test_constexpr() {
}
void test_exceptions() {
-#ifndef TEST_HAS_NO_EXCEPTIONS
+# ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
auto test = [&](auto&& v) {
@@ -176,7 +178,7 @@ void test_exceptions() {
assert(test(v));
}
-#endif
+# endif
}
// See https://llvm.org/PR31916
@@ -253,3 +255,5 @@ int main(int, char**) {
return 0;
}
+
+#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
index 6ff469290e44a5..f3f8f107c1b0f6 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
@@ -25,6 +25,8 @@
#include "test_macros.h"
#include "variant_test_helpers.h"
+#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
+
template <class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
@@ -353,3 +355,5 @@ int main(int, char**) {
return 0;
}
+
+#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
>From 3d760da2c2ad4cb3d6e97724330201518fd11099 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Thu, 18 Jan 2024 16:36:09 +0200
Subject: [PATCH 27/28] Try to fix CI
---
.../variant.visit.member/visit_return_type.pass.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
index f3f8f107c1b0f6..36f9f977042b1d 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
@@ -121,7 +121,7 @@ void test_argument_forwarding() {
std::move(cv).visit<ReturnType>(obj);
assert(Fn::check_call<const int&&>(val));
}
-#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
+# if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{ // single argument - lvalue reference
using V = std::variant<int&>;
int x = 42;
@@ -152,7 +152,7 @@ void test_argument_forwarding() {
std::move(cv).visit<ReturnType>(obj);
assert(Fn::check_call<int&&>(val));
}
-#endif
+# endif
}
template <typename ReturnType>
@@ -226,7 +226,7 @@ void test_constexpr_int() {
template <typename ReturnType>
void test_exceptions() {
-#ifndef TEST_HAS_NO_EXCEPTIONS
+# ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
auto test = [&](auto&& v) {
@@ -246,7 +246,7 @@ void test_exceptions() {
assert(test(v));
}
-#endif
+# endif
}
// See https://bugs.llvm.org/show_bug.cgi?id=31916
>From b2ced9e51b50c01e676d484aedb7939ac11a26d2 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Thu, 18 Jan 2024 16:59:44 +0200
Subject: [PATCH 28/28] Try to fix CI on AIX
---
.../robust_against_adl.pass.cpp | 6 ++----
.../variant/variant.visit.member/visit.pass.cpp | 14 ++++++--------
.../visit_return_type.pass.cpp | 14 ++++++--------
3 files changed, 14 insertions(+), 20 deletions(-)
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
index cf8dc028d9c41a..e7476a58983d22 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
@@ -8,6 +8,8 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// XFAIL: clang-16 || clang-17
+
// <variant>
// class variant;
@@ -20,8 +22,6 @@
#include "test_macros.h"
-#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
-
struct Incomplete;
template <class T>
struct Holder {
@@ -46,5 +46,3 @@ int main(int, char**) {
return 0;
}
-
-#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
index 7ef55b910dcfe9..f3801338583462 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
@@ -8,6 +8,8 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// XFAIL: clang-16 || clang-17
+
// <variant>
// class variant;
@@ -25,8 +27,6 @@
#include "test_macros.h"
#include "variant_test_helpers.h"
-#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
-
void test_call_operator_forwarding() {
using Fn = ForwardingCallObject;
Fn obj{};
@@ -80,7 +80,7 @@ void test_argument_forwarding() {
std::move(cv).visit(obj);
assert(Fn::check_call<const int&&>(val));
}
-# if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
+#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{ // single argument - lvalue reference
using V = std::variant<int&>;
int x = 42;
@@ -112,7 +112,7 @@ void test_argument_forwarding() {
std::move(cv).visit(obj);
assert(Fn::check_call<int&&>(val));
}
-# endif
+#endif
}
void test_return_type() {
@@ -158,7 +158,7 @@ void test_constexpr() {
}
void test_exceptions() {
-# ifndef TEST_HAS_NO_EXCEPTIONS
+#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
auto test = [&](auto&& v) {
@@ -178,7 +178,7 @@ void test_exceptions() {
assert(test(v));
}
-# endif
+#endif
}
// See https://llvm.org/PR31916
@@ -255,5 +255,3 @@ int main(int, char**) {
return 0;
}
-
-#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
index 36f9f977042b1d..f00e236f8de8cc 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
@@ -8,6 +8,8 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+// XFAIL: clang-16 || clang-17
+
// <variant>
// class variant;
@@ -25,8 +27,6 @@
#include "test_macros.h"
#include "variant_test_helpers.h"
-#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
-
template <class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
@@ -121,7 +121,7 @@ void test_argument_forwarding() {
std::move(cv).visit<ReturnType>(obj);
assert(Fn::check_call<const int&&>(val));
}
-# if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
+#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{ // single argument - lvalue reference
using V = std::variant<int&>;
int x = 42;
@@ -152,7 +152,7 @@ void test_argument_forwarding() {
std::move(cv).visit<ReturnType>(obj);
assert(Fn::check_call<int&&>(val));
}
-# endif
+#endif
}
template <typename ReturnType>
@@ -226,7 +226,7 @@ void test_constexpr_int() {
template <typename ReturnType>
void test_exceptions() {
-# ifndef TEST_HAS_NO_EXCEPTIONS
+#ifndef TEST_HAS_NO_EXCEPTIONS
ReturnArity obj{};
auto test = [&](auto&& v) {
@@ -246,7 +246,7 @@ void test_exceptions() {
assert(test(v));
}
-# endif
+#endif
}
// See https://bugs.llvm.org/show_bug.cgi?id=31916
@@ -355,5 +355,3 @@ int main(int, char**) {
return 0;
}
-
-#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800
More information about the cfe-commits
mailing list