13
13
#include < catch2/internal/catch_compare_traits.hpp>
14
14
#include < catch2/internal/catch_test_failure_exception.hpp>
15
15
#include < catch2/internal/catch_logical_traits.hpp>
16
+ #include < catch2/internal/catch_compiler_capabilities.hpp>
16
17
17
18
#include < type_traits>
18
19
#include < iosfwd>
34
35
# pragma GCC diagnostic ignored "-Wsign-compare"
35
36
#endif
36
37
38
+ #if defined(CATCH_CPP20_OR_GREATER) && __has_include(<compare>)
39
+ # include < compare>
40
+ # if defined( __cpp_lib_three_way_comparison ) && \
41
+ __cpp_lib_three_way_comparison >= 201907L
42
+ # define CATCH_CONFIG_CPP20_COMPARE_OVERLOADS
43
+ # endif
44
+ #endif
45
+
37
46
namespace Catch {
38
47
48
+ // Note: There is nothing that stops us from extending this,
49
+ // e.g. to `std::is_scalar`, but the more encompassing
50
+ // traits are usually also more expensive. For now we
51
+ // keep this as it used to be and it can be changed later.
52
+ template <typename T>
53
+ struct capture_by_value
54
+ : std::integral_constant<bool , std::is_arithmetic<T>{}> {};
55
+
56
+ #if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
57
+ template <>
58
+ struct capture_by_value <std::strong_ordering> : std::true_type {};
59
+ template <>
60
+ struct capture_by_value <std::weak_ordering> : std::true_type {};
61
+ template <>
62
+ struct capture_by_value <std::partial_ordering> : std::true_type {};
63
+ #endif
64
+
39
65
template <typename T>
40
66
struct always_false : std::false_type {};
41
67
@@ -44,11 +70,12 @@ namespace Catch {
44
70
bool m_result;
45
71
46
72
public:
47
- auto isBinaryExpression () const -> bool { return m_isBinaryExpression; }
48
- auto getResult () const -> bool { return m_result; }
49
- virtual void streamReconstructedExpression ( std::ostream &os ) const = 0;
73
+ constexpr auto isBinaryExpression () const -> bool { return m_isBinaryExpression; }
74
+ constexpr auto getResult () const -> bool { return m_result; }
75
+ // ! This function **has** to be overriden by the derived class.
76
+ virtual void streamReconstructedExpression ( std::ostream& os ) const ;
50
77
51
- ITransientExpression ( bool isBinaryExpression, bool result )
78
+ constexpr ITransientExpression ( bool isBinaryExpression, bool result )
52
79
: m_isBinaryExpression( isBinaryExpression ),
53
80
m_result( result )
54
81
{}
@@ -59,7 +86,7 @@ namespace Catch {
59
86
60
87
// We don't actually need a virtual destructor, but many static analysers
61
88
// complain if it's not here :-(
62
- virtual ~ITransientExpression (); // = default;
89
+ virtual ~ITransientExpression () = default ;
63
90
64
91
friend std::ostream& operator <<(std::ostream& out, ITransientExpression const & expr) {
65
92
expr.streamReconstructedExpression (out);
@@ -81,7 +108,7 @@ namespace Catch {
81
108
}
82
109
83
110
public:
84
- BinaryExpr ( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
111
+ constexpr BinaryExpr ( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
85
112
: ITransientExpression{ true , comparisonResult },
86
113
m_lhs ( lhs ),
87
114
m_op ( op ),
@@ -154,7 +181,7 @@ namespace Catch {
154
181
}
155
182
156
183
public:
157
- explicit UnaryExpr ( LhsT lhs )
184
+ explicit constexpr UnaryExpr ( LhsT lhs )
158
185
: ITransientExpression{ false , static_cast <bool >(lhs) },
159
186
m_lhs ( lhs )
160
187
{}
@@ -165,30 +192,30 @@ namespace Catch {
165
192
class ExprLhs {
166
193
LhsT m_lhs;
167
194
public:
168
- explicit ExprLhs ( LhsT lhs ) : m_lhs( lhs ) {}
195
+ explicit constexpr ExprLhs ( LhsT lhs ) : m_lhs( lhs ) {}
169
196
170
197
#define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR ( id, op ) \
171
198
template <typename RhsT> \
172
- friend auto operator op ( ExprLhs&& lhs, RhsT&& rhs ) \
199
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT&& rhs ) \
173
200
->std::enable_if_t< \
174
201
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
175
- Detail::negation<std::is_arithmetic< \
202
+ Detail::negation<capture_by_value< \
176
203
std::remove_reference_t <RhsT>>>>::value, \
177
204
BinaryExpr<LhsT, RhsT const &>> { \
178
205
return { \
179
206
static_cast <bool >( lhs.m_lhs op rhs ), lhs.m_lhs , #op##_sr, rhs }; \
180
207
} \
181
208
template <typename RhsT> \
182
- friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
209
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
183
210
->std::enable_if_t< \
184
211
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
185
- std::is_arithmetic <RhsT>>::value, \
212
+ capture_by_value <RhsT>>::value, \
186
213
BinaryExpr<LhsT, RhsT>> { \
187
214
return { \
188
215
static_cast <bool >( lhs.m_lhs op rhs ), lhs.m_lhs , #op##_sr, rhs }; \
189
216
} \
190
217
template <typename RhsT> \
191
- friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
218
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
192
219
->std::enable_if_t< \
193
220
Detail::conjunction< \
194
221
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
@@ -202,7 +229,7 @@ namespace Catch {
202
229
static_cast <bool >( lhs.m_lhs op 0 ), lhs.m_lhs , #op##_sr, rhs }; \
203
230
} \
204
231
template <typename RhsT> \
205
- friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
232
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
206
233
->std::enable_if_t< \
207
234
Detail::conjunction< \
208
235
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
@@ -220,28 +247,29 @@ namespace Catch {
220
247
221
248
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
222
249
250
+
223
251
#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR ( id, op ) \
224
252
template <typename RhsT> \
225
- friend auto operator op ( ExprLhs&& lhs, RhsT&& rhs ) \
253
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT&& rhs ) \
226
254
->std::enable_if_t< \
227
255
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
228
- Detail::negation<std::is_arithmetic< \
256
+ Detail::negation<capture_by_value< \
229
257
std::remove_reference_t <RhsT>>>>::value, \
230
258
BinaryExpr<LhsT, RhsT const &>> { \
231
259
return { \
232
260
static_cast <bool >( lhs.m_lhs op rhs ), lhs.m_lhs , #op##_sr, rhs }; \
233
261
} \
234
262
template <typename RhsT> \
235
- friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
263
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
236
264
->std::enable_if_t< \
237
265
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
238
- std::is_arithmetic <RhsT>>::value, \
266
+ capture_by_value <RhsT>>::value, \
239
267
BinaryExpr<LhsT, RhsT>> { \
240
268
return { \
241
269
static_cast <bool >( lhs.m_lhs op rhs ), lhs.m_lhs , #op##_sr, rhs }; \
242
270
} \
243
271
template <typename RhsT> \
244
- friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
272
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
245
273
->std::enable_if_t< \
246
274
Detail::conjunction< \
247
275
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
@@ -253,7 +281,7 @@ namespace Catch {
253
281
static_cast <bool >( lhs.m_lhs op 0 ), lhs.m_lhs , #op##_sr, rhs }; \
254
282
} \
255
283
template <typename RhsT> \
256
- friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
284
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
257
285
->std::enable_if_t< \
258
286
Detail::conjunction< \
259
287
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
@@ -274,16 +302,16 @@ namespace Catch {
274
302
275
303
#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR ( op ) \
276
304
template <typename RhsT> \
277
- friend auto operator op ( ExprLhs&& lhs, RhsT&& rhs ) \
305
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT&& rhs ) \
278
306
->std::enable_if_t< \
279
- !std::is_arithmetic <std::remove_reference_t<RhsT>>::value, \
307
+ !capture_by_value <std::remove_reference_t<RhsT>>::value, \
280
308
BinaryExpr<LhsT, RhsT const &>> { \
281
309
return { \
282
310
static_cast <bool >( lhs.m_lhs op rhs ), lhs.m_lhs , #op##_sr, rhs }; \
283
311
} \
284
312
template <typename RhsT> \
285
- friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
286
- ->std::enable_if_t<std::is_arithmetic <RhsT>::value, \
313
+ constexpr friend auto operator op ( ExprLhs&& lhs, RhsT rhs ) \
314
+ ->std::enable_if_t<capture_by_value <RhsT>::value, \
287
315
BinaryExpr<LhsT, RhsT>> { \
288
316
return { \
289
317
static_cast <bool >( lhs.m_lhs op rhs ), lhs.m_lhs , #op##_sr, rhs }; \
@@ -309,19 +337,23 @@ namespace Catch {
309
337
" wrap the expression inside parentheses, or decompose it" );
310
338
}
311
339
312
- auto makeUnaryExpr () const -> UnaryExpr<LhsT> {
340
+ constexpr auto makeUnaryExpr () const -> UnaryExpr<LhsT> {
313
341
return UnaryExpr<LhsT>{ m_lhs };
314
342
}
315
343
};
316
344
317
345
struct Decomposer {
318
- template <typename T, std::enable_if_t <!std::is_arithmetic<std::remove_reference_t <T>>::value, int > = 0 >
319
- friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const &> {
346
+ template <typename T,
347
+ std::enable_if_t <
348
+ !capture_by_value<std::remove_reference_t <T>>::value,
349
+ int > = 0 >
350
+ constexpr friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const &> {
320
351
return ExprLhs<const T&>{ lhs };
321
352
}
322
353
323
- template <typename T, std::enable_if_t <std::is_arithmetic<T>::value, int > = 0 >
324
- friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> {
354
+ template <typename T,
355
+ std::enable_if_t <capture_by_value<T>::value, int > = 0 >
356
+ constexpr friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> {
325
357
return ExprLhs<T>{ value };
326
358
}
327
359
};
0 commit comments