模板类默认构造requires子句能否访问后声明的静态成员函数?
静态成员函数
b对模板类s默认构造函数requires子句的可见性及C++20标准规定 问题
静态成员函数b是否对模板类s的默认构造函数的requires子句可见?C++20标准对该示例的合法性有何规定?
代码示例
template<auto...> struct s { s() requires (s::b()) = default; // Clang不支持,GCC、MSVC支持 static constexpr bool b() { return true; } }; static_assert((s<>{}, true));
编译器行为差异
- Clang:报错,认为
s中不存在成员b - GCC、MSVC:编译通过,符合标准预期
Clang报错信息(中文翻译)
<source>:3:22: 错误:'s<...>'中没有名为'b'的成员 3 | s() requires (s::b()) = default; | ~~~^ <source>:7:15: 错误:静态断言表达式不是整型常量表达式 7 | static_assert((s<>{}, true)); | ^~~~~~~~~~~~~ <source>:7:16: 注释:非constexpr构造函数's'不能用于常量表达式 7 | static_assert((s<>{}, true)); | ^ <source>:3:5: 注释:在此处声明 3 | s() requires (s::b()) = default; | ^
解答
可见性与合法性结论
根据C++20标准,静态成员函数b对默认构造函数的requires子句完全可见,该代码示例是合法的,Clang的报错属于编译器实现未跟上标准的问题。
标准依据
C++20标准中关于类成员作用域的规则明确:
- 类体的完整上下文特性:在类(包括模板类)的定义体内部,所有成员的作用域覆盖整个类体,声明顺序不影响同一类体内其他成员对它的引用(出自[class.mem]/6条款)。也就是说,即使
b的声明在构造函数之后,构造函数的requires子句仍能合法引用s::b()。 - 模板实例化的上下文规则:当模板被实例化时,类的所有成员都会被纳入完整类型的考量中,成员函数的requires子句会在类的完整类型上下文中求值(出自[temp.inst]/2条款),因此
b()的存在性和constexpr属性会被正确识别。
GCC和MSVC的实现符合上述标准规则,而Clang当前的实现未正确处理类内部requires子句对后续声明成员的引用,导致错误报错。
内容的提问来源于stack exchange,提问作者303
相关产品推荐
相关产品推荐

