嵌套requires子句中的常量表达式:Clang版本行为差异问询
关于Clang版本间Concept嵌套约束编译行为差异的疑问
我认为以下代码应触发编译器错误,因为requires子句中的嵌套约束并非常量表达式。但Clang 15.0.0可正常编译无报错,而Clang 14.0.0会触发预期错误,这似乎是行为退化。请问此行为变更是否有合理原因,还是单纯的Clang编译器bug?
struct s { static auto b() -> bool; }; template<typename T> concept c = requires { requires T::b(); }; static_assert(not c<s>); // fails with Clang 14, GCC 12.2, and MSVC 19.32
解答
这并非Clang的行为退化,而是对C++20标准规则的正确修正,具体原因如下:
标准规则明确
C++20标准规定,concept定义中嵌套的requires子句(如requires T::b();)需满足两个核心条件:
- 表达式
T::b()必须是潜在常量表达式(即具备在常量语境下求值的语法和声明基础,比如函数需标记为constexpr); - 该表达式在常量语境中求值的结果必须为
true。
旧版本编译器的实现偏差
Clang 14、GCC 12.2及MSVC 19.32的实现存在错误:它们未检查表达式是否为潜在常量表达式,仅判断语法合法性就认定约束成立。在你的代码中,s::b()是普通静态函数而非constexpr函数,本不应满足约束,但旧编译器误判c<s>为true,导致static_assert(not c<s>)失败。
Clang 15的修正
Clang 15严格遵循标准要求,正确校验了表达式的潜在常量属性:由于s::b()不具备constexpr声明,无法在常量语境下求值,因此requires T::b()约束不满足,c<s>为false,static_assert(not c<s>)自然通过编译。
综上,这个行为变更是符合C++20标准的修复,而非编译器bug。
内容的提问来源于stack exchange,提问作者303
相关产品推荐
相关产品推荐

