forked from sPHENIX-Collaboration/acts
/
TypeTraitsTest.cpp
236 lines (185 loc) · 6.69 KB
/
TypeTraitsTest.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
// This file is part of the Acts project.
//
// Copyright (C) 2019 CERN for the benefit of the Acts project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test.hpp>
#include "Acts/Utilities/TypeTraits.hpp"
namespace bdata = boost::unit_test::data;
namespace tt = boost::test_tools;
using namespace Acts::concept;
namespace Acts {
namespace Test {
BOOST_AUTO_TEST_SUITE(Surfaces)
// generate traits for methods named foo and bar
METHOD_TRAIT(foo_method_t, foo);
METHOD_TRAIT(bar_method_t, bar);
struct E {
int bar(const double&) { return 5; }
};
struct E2 {
int bar(const double&) const { return 5; }
};
class E3 {
int bar(const double&) { return 5; }
};
BOOST_AUTO_TEST_CASE(TypeTraitsMethods) {
// E does not have a method bar without arguments
static_assert(!has_method<E, int, bar_method_t>, "failed");
// E does have a method like int bar(const double&)
static_assert(has_method<E, int, bar_method_t, const double&>, "failed");
// E does not have method bar returning double instead of int
static_assert(!has_method<E, double, bar_method_t, const double&>, "failed");
// E does not have method taking non-ref const double argument
static_assert(!has_method<E, int, bar_method_t, const double>, "failed");
// E does not have method taking non-const double ref argument
static_assert(!has_method<E, int, bar_method_t, double&>, "failed");
// E does not have method taking plain double argument
static_assert(!has_method<E, int, bar_method_t, double>, "failed");
// E does not have method const method with correct signature otherwise
// This test ensures a non-const method does not qualify for a
// check for a method on the const type
static_assert(!has_method<const E, int, bar_method_t, const double&>,
"failed");
// E does not have a foo method
static_assert(!has_method<E, int, foo_method_t, const double&>, "failed");
// E2 doesnt have method like int bar()
static_assert(!has_method<E2, int, bar_method_t>, "failed");
// E2 does not have non-const method with signature int bar(const double&)
// This means that a const method won't fulfill a non-const method
// requirement
static_assert(!has_method<E2, int, bar_method_t, const double&>, "failed");
// E2 has method of signature int bar(const double&) const
static_assert(has_method<const E2, int, bar_method_t, const double&>,
"failed");
// E2 does not have method taking non-ref const double
static_assert(!has_method<E2, int, bar_method_t, const double>, "failed");
// E2 does not have method taking non-const ref double
static_assert(!has_method<E2, int, bar_method_t, double&>, "failed");
// E2 does not have method taking plain double
static_assert(!has_method<E2, int, bar_method_t, double>, "failed");
// E2 does not have method with char return type
static_assert(!has_method<const E2, char, bar_method_t, const double&>,
"failed");
// E2 does not have foo method
static_assert(!has_method<const E2, int, foo_method_t, const double&>,
"failed");
// E3 does have a method like int bar(const double&) but is private
static_assert(!has_method<E3, int, bar_method_t, const double&>, "failed");
}
// trait for member named "member_a"
template <typename T>
using member_a_t = decltype(std::declval<T>().member_a);
// trait for member named "member_b"
template <typename T>
using member_b_t = decltype(std::declval<T>().member_b);
struct M {
int member_a;
double member_b;
};
struct M2 {
double member_a;
};
struct M3 {
char member_a;
};
struct M4 {
char member_b;
};
class M5 {
char member_b;
};
BOOST_AUTO_TEST_CASE(TypeTraitsMember) {
static_assert(has_member<M, member_a_t, int>, "!");
static_assert(has_member<M, member_b_t, double>, "!");
// incorrect type
static_assert(!has_member<M, member_b_t, int>, "!");
static_assert(!has_member<M, member_a_t, double>, "!");
static_assert(has_member<M2, member_a_t, double>, "!");
static_assert(!has_member<M2, member_a_t, int>, "!");
static_assert(exists<member_a_t, M>, "!");
static_assert(exists<member_a_t, M2>, "!");
static_assert(exists<member_a_t, M3>, "!");
static_assert(!exists<member_a_t, M4>, "!");
// private member is not detected
static_assert(!has_member<M5, member_b_t, char>, "!");
// private member is not detected.
static_assert(!exists<member_b_t, M5>, "!");
}
template <typename T>
using nested_a_t = typename T::NestedA;
template <typename T>
using nested_b_t = typename T::NestedB;
struct N {
struct NestedA;
class NestedB;
};
struct N2 {
struct NestedA;
};
struct N3 {
class NestedB;
};
BOOST_AUTO_TEST_CASE(TypeTraitsNestedType) {
static_assert(exists<nested_a_t, N>, "!");
static_assert(exists<nested_b_t, N>, "!");
static_assert(exists<nested_a_t, N2>, "!");
static_assert(!exists<nested_b_t, N2>, "!");
static_assert(!exists<nested_a_t, N3>, "!");
static_assert(exists<nested_b_t, N3>, "!");
}
// trait for member named "member"
template <typename T>
using member_t = decltype(std::declval<T>().member);
// trait for nested type called "Nested"
template <typename T>
using nested_t = typename T::Nested;
// trait for contained template "meta" with two template params
template <typename T>
using meta_t = typename T::template meta<void, void>;
// combine it into a concept
template <typename T>
constexpr bool SomeConcept =
require<has_method<T, double, foo_method_t, double, int>,
has_method<const T, bool, bar_method_t, double&&>,
has_member<T, member_t, bool>, exists<nested_t, T>,
exists<meta_t, T>>;
struct A {
bool member;
struct Nested {};
template <typename U, typename V>
struct meta {};
double foo(double, int) { return 5; }
bool bar(double&&) const { return true; }
};
struct A2 {
bool member;
struct Nested {};
template <typename U>
struct meta {};
double foo(double, int) { return 5; }
bool bar(double&&) const { return true; }
};
struct B {
bool different;
int foo(double) { return 5; }
};
struct C {
double foo(int) { return 5; }
};
struct D {
double bar(double) { return 5; }
};
BOOST_AUTO_TEST_CASE(TypeTraitsConcepts) {
static_assert(SomeConcept<A>, "A does not fulfill \"SomeConcept\"");
static_assert(!SomeConcept<A2>, "A2 does not fulfill \"SomeConcept\"");
static_assert(!SomeConcept<B>, "B does fulfill \"SomeConcept\"");
static_assert(!SomeConcept<C>, "C does fulfill \"SomeConcept\"");
static_assert(!SomeConcept<D>, "D does fulfill \"SomeConcept\"");
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace Test
} // namespace Acts