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?
CodePudding user response:
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>;