GCC 10.2编译模板默认实参中ad-hoc requires表达式报错原因
两种编译行为差异的根本原因
这个编译报错并非代码违反C语言规则,本质是GCC 10.2版本对C20 requires表达式的实现缺陷导致的。
标准层面的合法性判定
按照C++20对ad-hoc requires表达式的语法定义:
requires (parameter-list_opt) { requirement-seq }
这类表达式完全允许在前置括号内声明形式参数。这类参数属于仅在后续需求序列的语义校验上下文中生效的虚构实体,不需要实际构造对象、也不对应任何运行时存储实体。
从标准规则判断,requires(T const& x){ x.foo(); }是完全合法的写法:它的语义就是校验“给定一个T const&类型的左值x,是否可以无参数调用x.foo()成员函数”。
编译器实现的错误判定逻辑
GCC 10.2的前端在处理模板声明域内、处于模板形参默认实参位置的requires表达式时,对requires引入的形式参数存在作用域判定的缺陷:
- 当requires的需求序列中直接引用之前声明的参数x时,前端会错误将x识别为“具有自动存储期的局部变量”,触发编译规则检查——自动存储期的局部变量不允许出现在模板形参的默认实参上下文中(默认实参需要满足编译期可即时求值的要求,不能绑定运行时栈上的实体),因此抛出
local variable 'x' may not appear in this context的报错。 - 当将x替换为
std::declval<T const&>().foo()的写法时,这段表达式没有引入任何具名的局部变量实体,完全绕开了GCC对requires参数名的错误作用域判定逻辑,因此可以正常通过编译。
补充说明:该问题属于GCC的已知实现bug,从GCC 11版本开始已经完成修复,带命名参数的requires写法在新版GCC上可以完全按照标准规则正常编译。
内容的提问来源于stack exchange,提问作者Fytch
相关产品推荐
相关产品推荐

