'how to evaluate concept to false upon expression compilation error
I was trying to change the following example concept code that, under certain inputs, caused an error instead of evaluating false:
template <typename T>
constexpr bool inner = T::prop;
template <typename T>
concept outer = inner<T>;
struct pass {static constexpr bool prop = true;};
struct fail {static constexpr bool prop = false;};
struct bad_fail {static constexpr std::tuple<> prop{};};
static_assert(outer<pass>);
static_assert(not outer<fail>);
static_assert(not outer<bad_fail>);
This has compile error cannot convert 'const std::tuple<>' to 'const bool'.
I attempted to only evaluate inner when it would compile using a requires clause:
template <typename T>
constexpr bool inner = T::prop;
template <typename T>
concept outer = []() consteval -> bool {
if constexpr (
requires() {{
inner<T>
} -> std::same_as<const bool&>;}
) {
return inner<T>;
} else {
return false;
}
}();
struct pass {static constexpr bool prop = true;};
struct fail {static constexpr bool prop = false;};
struct bad_fail {static constexpr std::tuple<> prop{};};
static_assert(outer<pass>);
static_assert(not outer<fail>);
static_assert(not outer<bad_fail>);
This results in a confusing error:
error: non-constant condition for static assertion ... static_assert(not outer<bad_fail>)
And the same cannot convert 'const std::tuple<>' to 'const bool' which appears to be from the 2nd inner. (The compiler does not specify)
I then attempted to combine the compilation check and truth check into a static_assert check within a requires clause:
template <typename T>
constexpr bool inner = T::prop;
template <typename T>
concept outer = requires() {{
[]() constexpr {
static_assert(inner<T>);
}()
} -> std::same_as<void>;};
struct pass {static constexpr bool prop = true;};
struct fail {static constexpr bool prop = false;};
struct bad_fail {static constexpr std::tuple<> prop{};};
static_assert(outer<pass>);
static_assert(not outer<fail>);
//static_assert(not outer<bad_fail>);
This results in a confusing error:
error: static assertion failed ... static_assert(not outer<fail>)
This is confusing because:
error: static assertion failed ... static_assert(inner<T>)
Is also thrown, implying that static_assert escapes requires clauses. Which sure enough is true:
template <std::monostate>
concept should_false = requires() {{
[]() constexpr {
static_assert(false);
}()
} -> std::same_as<void>;};
As this has compile error error: static assertion failed ... static_assert(false)!
How can I have outer<bad_fail> evaluate to false with no compilation errors?
Solution 1:[1]
You can use requires-clause to initialize inner, which first requires that the return type of T::prop must be const bool&, then use nested requires with T::prop as its value
#include <concepts>
template <typename T>
constexpr bool inner = requires {
{T::prop} -> std::same_as<const bool&>;
requires T::prop;
};
template <typename T>
concept outer = inner<T>;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
