被删除的函数模板在requires表达式中的编译器行为差异及合规性问询
函数模板特化检测的C++20标准合规性分析
我们针对主模板被删除但存在特化版本的函数模板f<T>,使用requires表达式检测其是否被特化,以下是三个代码版本的合规性与编译器问题分析:
版本1:requires表达式直接引用f<T>
- 代码特征:在requires表达式中直接写
f<T>(无函数调用语法) - 标准合规性:完全符合C++20标准。在requires表达式的表达式约束中,函数模板特化的名称
f<T>本身是合法的左值表达式,只要该特化存在(即被显式特化过),这个约束就应该成立。 - 编译器问题:GCC和MSVC无法编译此版本属于编译器实现bug,它们错误地拒绝了合法的表达式检测逻辑。
版本2:requires表达式使用f<T>()调用语法
- 代码特征:将requires表达式中的
f<T>修改为f<T>()(添加函数调用操作) - 标准合规性:符合C++20标准。此时检测的是
f<T>是否可被调用,由于主模板已被删除,只有存在可调用的显式特化版本时,该约束才会满足。这是另一种合法的特化检测方式。 - 编译器情况:GCC能够编译此版本,说明它对调用式的约束检测逻辑更完善;MSVC仍无法编译此版本的话,同样属于MSVC的实现bug。
版本3:使用命名concept替换内联requires表达式
- 代码特征:将内联的requires约束封装为命名concept
- 标准合规性:符合C++20标准。命名concept只是对原有约束的封装,本质逻辑与版本1、2一致,并未改变标准合规性。
- 编译器情况:三款编译器均能编译,说明它们对命名concept的处理逻辑没有触发之前的实现缺陷,是兼容性更好的写法。
总结
三个版本均为符合C++20标准的良构代码。其中:
- GCC和MSVC无法编译版本1属于编译器bug;
- MSVC无法编译版本2也属于编译器bug;
- 版本3的写法避开了编译器的实现缺陷,因此兼容性最优。
内容的提问来源于stack exchange,提问作者jcai
相关产品推荐
相关产品推荐

