blob: a2e4183854a0a3fb74028a8424d7df0108e57fd8 [file] [log] [blame]
// Copyright (C) 2019-2025 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-do run { target c++26 } }
#include <variant>
#if __cpp_lib_variant < 202306L
# error __cpp_lib_variant has the wrong value in <variant>
#endif
#include <functional> // reference_wrapper
#include <testsuite_hooks.h>
void
test01()
{
// Verify that visitation uses INVOKE and supports a pointer-to-member.
struct X { int n; };
using V = std::variant<X, X*, std::reference_wrapper<X>>;
struct Derv : private V {
using V::V;
using V::visit;
};
Derv v{X{1}};
static_assert( std::is_same_v<decltype(v.visit(&X::n)), int&> );
// Verify that constness and value category are correctly forwarded.
std::variant<int> v2{1};
auto id = []<typename T>(T&& t) -> T&& { return std::forward<T>(t); };
static_assert( std::is_same_v<decltype(v2.visit(id)), int&> );
static_assert( std::is_same_v<decltype(std::move(v2).visit(id)), int&&> );
const auto& vc = v2;
static_assert( std::is_same_v<decltype(vc.visit(id)), const int&> );
static_assert( std::is_same_v<decltype(std::move(vc).visit(id)), const int&&> );
static_assert( std::is_same_v<decltype(vc.visit<void>(id)), void> );
}
void
test02()
{
struct NoCopy
{
NoCopy() { }
NoCopy(const NoCopy&) = delete;
NoCopy(NoCopy&&) = delete;
~NoCopy() { }
int operator()(int i) { return i; }
int operator()(const NoCopy&) { return 100; }
};
std::variant<NoCopy, int> v{10};
NoCopy f;
// Visit should not need arguments to be copyable:
int res = v.visit(f);
VERIFY( res == 10 );
v.emplace<NoCopy>();
res = v.visit(f);
VERIFY( res == 100 );
res = v.visit<bool>(f);
VERIFY( res == 1 );
}
void
test03()
{
// Verify that member visit can access the variant as a private base class.
struct Derived : private std::variant<int>
{
using variant::visit;
};
Derived d;
int i = d.visit([](int& x) { return --x; });
VERIFY( i == -1 );
unsigned u = d.visit<unsigned>([](int x) { return x; });
VERIFY( u == -1u );
}
void
test04()
{
struct A { char a = 'a'; };
struct B { char b = 'b'; };
struct C { char c = 'c'; };
auto f = [](auto x) { return B{}; };
using State = std::variant<A, B, C>;
State state = A{};
auto res = std::move(state).visit<State>(f);
// Verify that visit<R> only matches the explicit return type overload.
static_assert( std::is_same_v<decltype(res), State> );
}
int
main()
{
test01();
test02();
test03();
test04();
}