|
11 | 11 | LIBASSERT_BEGIN_NAMESPACE |
12 | 12 | namespace detail { |
13 | 13 |
|
14 | | -std::false_type is_referencable_expression(...); |
| 14 | +template <typename Concept, typename = void> |
| 15 | +inline constexpr bool is_referencable_expression_impl = false; |
15 | 16 |
|
16 | 17 | template <typename Concept> |
17 | | -auto is_referencable_expression(Concept c) |
18 | | - -> decltype(c(detail::expression_decomposer<>{}), std::true_type{}); |
| 18 | +inline constexpr bool is_referencable_expression_impl< |
| 19 | + Concept, |
| 20 | + decltype(void(std::declval<Concept>()(detail::expression_decomposer{})))> = true; |
19 | 21 |
|
| 22 | +template <typename Concept> |
| 23 | +constexpr bool is_referencable_expression(const Concept&) { |
| 24 | + return is_referencable_expression_impl<Concept>; |
| 25 | +} |
20 | 26 | // A macro that checks whether an expression can be decomposed by the |
21 | 27 | // decomposer. An expression that fails is a bitfield for example. |
22 | | -#define LIBASSERT_IS_DECOMPOSABLE_EXPR(expr) \ |
23 | | - decltype(libassert::detail::is_referencable_expression( \ |
24 | | - [](auto expr_decomposer) -> decltype(std::move(expr_decomposer) \ |
25 | | - << expr) {}))::value |
| 28 | +#define LIBASSERT_IS_DECOMPOSABLE_EXPR(expr) \ |
| 29 | + libassert::detail::is_referencable_expression( \ |
| 30 | + [&](auto expr_decomposer, \ |
| 31 | + int = \ |
| 32 | + (void(libassert_expr_decomposer_t{} << expr), 0)) {}) |
26 | 33 |
|
27 | 34 | // The decomposer is passed as a template parameter to not evaluate the other |
28 | 35 | // path and cause a hard error |
29 | 36 | #define LIBASSERT_DECOMPOSER(expr) \ |
30 | 37 | [&](auto decomposer) { \ |
| 38 | + using libassert_expr_decomposer_t = std::conditional_t<sizeof(decomposer) != 0,libassert::detail::expression_decomposer<>,void>;\ |
31 | 39 | if constexpr (sizeof(decomposer) && \ |
32 | 40 | LIBASSERT_IS_DECOMPOSABLE_EXPR(expr)) { \ |
33 | 41 | return libassert::detail::expression_decomposer(std::move(decomposer) \ |
|
0 commit comments