C++20 中的 requires-expression 可以隐式转换为 bool 类型吗?

Can requires-expression in C++20 be of type implicitly convertible to bool?

在以下示例中,第二个 f 函数重载的 requires 表达式具有类型 std::integral_constant<bool,true>,可隐式转换为 bool:

#include <type_traits>

struct S {
    static constexpr bool valid = true;
};

template<typename T>
int f() { return 1; }
template<typename T>
int f() requires( std::bool_constant< T::valid >() ) { return 2; }

int main() {
    return f<S>();
}

可以观察到 GCC 拒绝了程序,因为类型不准确 bool,但 Clang 接受了,但选择了另一个重载 int f() { return 1; }。演示:https://gcc.godbolt.org/z/nf65zrxoK

这里哪个编译器是正确的?

我相信 GCC 是正确的——类型必须 bool 完全符合 [temp.constr.atomic]/3(注意这里的 Estd::bool_constant< T::valid >()):

To determine if an atomic constraint is satisfied, the parameter mapping and template arguments are first substituted into its expression. If substitution results in an invalid type or expression, the constraint is not satisfied. Otherwise, the lvalue-to-rvalue conversion is performed if necessary, and E shall be a constant expression of type bool. The constraint is satisfied if and only if evaluation of E results in true. If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required. [ Example:

template<typename T> concept C =
  sizeof(T) == 4 && !true;      // requires atomic constraints sizeof(T) == 4 and !true

template<typename T> struct S {
  constexpr operator bool() const { return true; }
};

template<typename T> requires (S<T>{})
void f(T);                      // #1
void f(int);                    // #2

void g() {
  f(0);                         // error: expression S<int>{} does not have type bool
}                               // while checking satisfaction of deduced arguments of #1;
                                // call is ill-formed even though #2 is a better match

— end example ]