Audacity 3.2.0
VariantTest.cpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*!********************************************************************
3
4 Audacity: A Digital Audio Editor
5
6 VariantTest.cpp
7
8 Paul Licameli
9
10**********************************************************************/
11#include <catch2/catch.hpp>
12
13#include "Callable.h"
14#include "Variant.h"
15using namespace Variant;
16
18
19// Not yet varied in these tests
20struct ValueType {
21 int x;
22 operator int() const { return x; }
23};
24// Also works with
25// using ValueType = int;
26
28template<bool Const, Ref ref = lvalue>
29struct Tester {
30
31template<typename T>
32using MaybeConst = std::conditional_t<Const, const T, T>;
33
34using ResultType = std::conditional_t<ref == noref,
36 std::conditional_t<ref == rvalue,
37 std::add_rvalue_reference_t<MaybeConst<ValueType>>,
38 std::add_lvalue_reference_t<MaybeConst<ValueType>>
39 >
40>;
41
42template<int Value>
43static ResultType value() {
44 static MaybeConst<ValueType> x{ Value };
45 if constexpr (ref == rvalue)
46 return std::move(x);
47 else
48 return x;
49}
50
51struct X {
53};
55struct Y {
56 template<bool C> auto memberfunction()
57 -> std::enable_if_t<!C, ResultType> { return value<1>(); }
58 template<bool C> auto memberfunction() const
59 -> std::enable_if_t<C, ResultType> { return value<1>(); }
60};
62struct Z {
63 ResultType constmemberfunction() const { return value<2>(); }
64};
65static ResultType nakedFunction(float) { return value<3>(); }
66static auto moveOnly() {
67 // Note: remove trailing return type and compilation of Visit correctly
68 // breaks because a value, not reference results for one alternative
69 return [u = std::make_unique<X>()](double) -> ResultType
70 { return value<4>(); };
71}
72struct CopyOnly{
73 CopyOnly() = default;
74 CopyOnly(const CopyOnly&) = default;
75 CopyOnly(CopyOnly&&) = delete;
76
77 ResultType operator() (long double) const & { return value<5>(); }
78 ResultType operator() (long double) const && { return value<6>(); }
79 ResultType operator() (long double) & { return value<7>(); }
80 ResultType operator() (long double) && { return value<8>(); }
81};
82
83// INVOKE-ing pointer to member always gives lvalue references.
84// So if &X::member below is one of the captured invocables,
85// and the given variant can contain X,
86// then the visitor returns an lvalue reference for the X alternative,
87// therefore it must also return a reference for all alternatives.
88using VariantType = std::conditional_t<ref == lvalue,
89 std::variant<
96 >,
97 std::variant<
98 // omit X
104 >
105>;
106
107template<typename Visitor, typename Arg>
108static void testCase(const Visitor &visitor, int result, Arg &arg)
109{
110 if constexpr(Const)
111 {
112 const std::remove_reference_t<decltype(arg)> carg{ arg };
113 const VariantType cv{ carg };
114 REQUIRE(result == visitor(carg));
115 REQUIRE(result == Visit(visitor, cv));
116 if constexpr (ref != lvalue) {
117 REQUIRE(result == visitor(std::move(carg)));
118 REQUIRE(result == Visit(visitor, move(cv)));
119 }
120 }
121
122 {
123 VariantType v{ arg };
124 REQUIRE(result == visitor(arg));
125 REQUIRE(result == Visit(visitor, v));
126 if constexpr (ref != lvalue) {
127 REQUIRE(result == visitor(std::move(arg)));
128 REQUIRE(result == Visit(visitor, move(v)));
129 }
130 }
131};
132
134{
135 // Callable::OverloadSet can capture many kinds of things. Test each.
136 // This also tests compilation of the variadic constructor of OverloadSet
137 // which can take a mix of l- and rvalues.
138 CopyOnly copyOnly;
139 const auto visitor = Callable::OverloadSet(
140 &X::member,
141 &Y::template memberfunction<Const>,
144 moveOnly(),
145 copyOnly
146 );
147
148 X x;
149 Y y;
150 Z z;
151 float f{};
152 double d{};
153 long double ld{};
154
155 // Pointer to data member, captured as INVOKE-able, can only return lvalue
156 // references, so it is excluded from other test cases
157 if constexpr (ref == lvalue)
158 testCase(visitor, 0, x);
159
160 testCase(visitor, 1, y);
161 testCase(visitor, 2, z);
162 testCase(visitor, 3, f);
163 testCase(visitor, 4, d);
164 testCase(visitor, 5, ld);
165
166 // An invocable can distinguish its own value category and constness
167 REQUIRE(6 == std::move(visitor)(ld));
168 using ConstVisitorType = decltype(visitor);
169 using VisitorType = std::remove_const_t<ConstVisitorType>;
170 auto &mutVisitor = const_cast<VisitorType&>(visitor);
171 REQUIRE(7 == mutVisitor(ld));
172 REQUIRE(8 == std::move(mutVisitor)(ld));
173}
174
175}; // stateless struct Tester
176
177TEST_CASE("Variant visitors returning T &")
178{
180}
181
182TEST_CASE("Variant visitors returning T const &")
183{
185}
186
187TEST_CASE("Variant visitors returning T &&")
188{
190}
191
192TEST_CASE("Variant visitors returning T const &&")
193{
195}
196
197TEST_CASE("Variant visitors returning T")
198{
200}
201
202TEST_CASE("Variant visitors returning T const")
203{
205}
206
208 static int x;
209 int & operator () (std::monostate) const { return x; }
210};
211
212// Visit() can be called for a proper subclasses of a std::variant<> too
213struct TestVariant : std::variant<std::monostate> {};
214
215static void compileTest()
216{
217 // Test compilation of all 16 combinations of constness and value category
218 // of the visitor and the variant
219
220 // This is an example that fails to compile when decltype(auto) in Variant.h
221 // is replaced with auto
222 TestVariant var;
223 const TestVariant cvar;
224 TestVisitor vis;
225 const TestVisitor cvis;
226
227 static_assert(std::is_same_v<int&, decltype(Visit(vis, var))>);
228 static_assert(std::is_same_v<int&, decltype(Visit(cvis, var))>);
229 static_assert(std::is_same_v<int&, decltype(Visit(std::move(vis), var))>);
230 static_assert(std::is_same_v<int&, decltype(Visit(std::move(cvis), var))>);
231
232 static_assert(std::is_same_v<int&, decltype(Visit(vis, cvar))>);
233 static_assert(std::is_same_v<int&, decltype(Visit(cvis, cvar))>);
234 static_assert(std::is_same_v<int&, decltype(Visit(std::move(vis), cvar))>);
235 static_assert(std::is_same_v<int&, decltype(Visit(std::move(cvis), cvar))>);
236
237 static_assert(std::is_same_v<int&, decltype(Visit(vis, std::move(var)))>);
238 static_assert(std::is_same_v<int&, decltype(Visit(cvis, std::move(var)))>);
239 static_assert(std::is_same_v<int&, decltype(Visit(std::move(vis), std::move(var)))>);
240 static_assert(std::is_same_v<int&, decltype(Visit(std::move(cvis), std::move(var)))>);
241
242 static_assert(std::is_same_v<int&, decltype(Visit(vis, std::move(cvar)))>);
243 static_assert(std::is_same_v<int&, decltype(Visit(cvis, std::move(cvar)))>);
244 static_assert(std::is_same_v<int&, decltype(Visit(std::move(vis), std::move(cvar)))>);
245 static_assert(std::is_same_v<int&, decltype(Visit(std::move(cvis), std::move(cvar)))>);
246}
Functions and classes that generate callable objects.
emulates std::visit for one visitor
static void compileTest()
TEST_CASE("Variant visitors returning T &")
Ref
Definition: VariantTest.cpp:17
@ rvalue
Definition: VariantTest.cpp:17
@ lvalue
Definition: VariantTest.cpp:17
@ noref
Definition: VariantTest.cpp:17
OverloadSet(Is &&... invocables) -> OverloadSet< Is &&... >
MENUS_API void Visit(Visitor< Traits > &visitor, AudacityProject &project)
STL namespace.
int & operator()(std::monostate) const
static int x
ResultType operator()(long double) const &
Definition: VariantTest.cpp:77
CopyOnly(CopyOnly &&)=delete
CopyOnly(const CopyOnly &)=default
CopyOnly()=default
ValueType member
Definition: VariantTest.cpp:52
Structure can specialize with only a non-const member function.
Definition: VariantTest.cpp:55
auto memberfunction() const -> std::enable_if_t< C, ResultType >
Definition: VariantTest.cpp:58
auto memberfunction() -> std::enable_if_t<!C, ResultType >
Definition: VariantTest.cpp:56
Structure always with a const member function.
Definition: VariantTest.cpp:62
ResultType constmemberfunction() const
Definition: VariantTest.cpp:63
Parameterize for the type of visitor return.
Definition: VariantTest.cpp:29
static ResultType value()
Definition: VariantTest.cpp:43
static ResultType nakedFunction(float)
Definition: VariantTest.cpp:65
std::conditional_t< ref==noref, MaybeConst< ValueType >, std::conditional_t< ref==rvalue, std::add_rvalue_reference_t< MaybeConst< ValueType > >, std::add_lvalue_reference_t< MaybeConst< ValueType > > > > ResultType
Definition: VariantTest.cpp:40
std::conditional_t< Const, const T, T > MaybeConst
Definition: VariantTest.cpp:32
static void testCase(const Visitor &visitor, int result, Arg &arg)
static auto moveOnly()
Definition: VariantTest.cpp:66
void DoTests()
std::conditional_t< ref==lvalue, std::variant< MaybeConst< X >, MaybeConst< Y >, MaybeConst< Z >, MaybeConst< float >, MaybeConst< double >, MaybeConst< long double > >, std::variant< MaybeConst< Y >, MaybeConst< Z >, MaybeConst< float >, MaybeConst< double >, MaybeConst< long double > > > VariantType