如何在表达式编译错误时将概念评估为假

how to evaluate concept to false upon expression compilation error

我试图更改以下示例概念代码,该代码在某些输入下导致错误而不是评估 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>);

这有编译错误 cannot convert 'const std::tuple<>' to 'const bool'

我试图只评估 inner 当它使用 requires 子句编译时:

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>);

这会导致一个令人困惑的错误:

error: non-constant condition for static assertion ... static_assert(not outer<bad_fail>)

同样的 cannot convert 'const std::tuple<>' to 'const bool' 似乎来自第二个 inner。 (编译器不指定)

然后我尝试将编译检查和真实性检查合并到 requires 子句中的 static_assert 检查中:

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>);

这会导致一个令人困惑的错误:

error: static assertion failed ... static_assert(not outer<fail>)

这令人困惑,因为:

error: static assertion failed ... static_assert(inner<T>)

也被抛出,暗示 static_assert 转义 requires 子句。果然是真的:

template <std::monostate>
concept should_false = requires() {{
    []() constexpr {
        static_assert(false);
    }()
} -> std::same_as<void>;};

因为这有编译错误error: static assertion failed ... static_assert(false)!

如何让 outer<bad_fail> 计算为 false 而没有编译错误?

可以使用requires子句初始化inner,首先要求T::prop的return类型必须是const bool&,然后使用嵌套 requires,其值 T::prop

#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>;

Demo