[libcxx] [clang] [llvm] [libc] [compiler-rt] [clang-tools-extra] [lldb] [flang] [libc++][variant] P2637R3 - Member `visit` (PR #76447)
Hristo Hristov via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 27 07:48:21 PST 2023
https://github.com/H-G-Hristov created https://github.com/llvm/llvm-project/pull/76447
Implements parts of: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2637r3.html (https://eel.is/c++draft/variant.visit)
Adds member `visit` tests and (NFC) refactors + reformats the non-member `visit` tests to accomodate the member `visit` additions for consistency.
>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/10] [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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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
More information about the cfe-commits
mailing list