Fed*_*dor 11 c++ language-lawyer c++20 requires-clause
在以下示例中,第二个f函数重载的需要表达式的类型为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>();
}
Run Code Online (Sandbox Code Playgroud)
可以观察到,GCC 由于类型不精确而拒绝该程序bool,但 Clang 接受,但选择了另一个重载int f() { return 1; }。演示: https: //gcc.godbolt.org/z/nf65zrxoK
这里哪个编译器是正确的?
我相信 GCC 是正确的\xe2\x80\x94类型必须bool完全符合[temp.constr.atomic]/3(请注意,E这里是std::bool_constant< T::valid >()):
\n\n为了确定是否满足原子约束,首先将参数映射和模板实参替换到其表达式中。如果替换导致无效类型或表达式,则不满足约束。否则,如有必要,将执行左值到右值的转换,并且 E 应为 bool 类型的常量表达式。当且仅当 E 的计算结果为真时,约束才被满足。如果在程序的不同点,对于相同的原子约束和模板参数,满足结果不同,则该程序是格式错误的,不需要诊断。[ 例子:
\nRun Code Online (Sandbox Code Playgroud)\ntemplate<typename T> concept C =\n sizeof(T) == 4 && !true; // requires atomic constraints sizeof(T) == 4 and !true\n\ntemplate<typename T> struct S {\n constexpr operator bool() const { return true; }\n};\n\ntemplate<typename T> requires (S<T>{})\nvoid f(T); // #1\nvoid f(int); // #2\n\nvoid g() {\n f(0); // error: expression S<int>{} does not have type bool\n} // while checking satisfaction of deduced arguments of #1;\n // call is ill-formed even though #2 is a better match\n\xe2\x80\x94 结束示例]
\n