带trailing requires子句的类外模板成员函数定义合法形式问询
C++类成员模板trailing requires子句中嵌套类型的引用问题
以下代码展示了类A包含嵌套类型B,其模板成员函数的trailing requires子句引用嵌套类型B,并在类外定义这些函数的场景:
template <typename X, typename Y> concept C = true; struct A { struct B {}; template <typename T> void f1() requires C<T, A::B>; template <typename T> void f2() requires C<T, A::B>; template <typename T> void f3() requires C<T, B>; template <typename T> void f4() requires C<T, B>; }; template <typename T> inline void A::f1() requires C<T, A::B> {} template <typename T> inline void A::f2() requires C<T, B> {} template <typename T> inline void A::f3() requires C<T, A::B> {} template <typename T> inline void A::f4() requires C<T, B> {} int main() { A{}.f1<A::B>(); A{}.f2<A::B>(); A{}.f3<A::B>(); A{}.f4<A::B>(); }
我无法找到或明确理解以下问题的权威标准表述:
- trailing requires子句是否可像尾随返回类型那样,无需显式限定即可引用嵌套类型
- 合规的编译器实现应接受
f2、f3、f4中的哪些定义
在C++标准草案中,最接近的内容来自[temp.mem]章节:
在类模板定义外部定义的类模板成员模板,应指定与类模板等效的模板头,后跟与成员模板等效的模板头(13.7.6.1)。
其中13.7.6.1引用了[temp.over.link]第7段:
若两个函数模板在同一作用域中声明、同名、具有等效的模板头,且返回类型、参数列表和trailing requires子句(若有)使用上述规则比较涉及模板参数的表达式后等效,则这两个函数模板等效。
对于requires子句本身,等效性由以下规则指定:
两者均有requires子句,且对应的约束表达式等效。
在其他语境下,我认为f1至f4的所有约束形式在形式上都是等效的,但我对标准的熟悉程度不足以自行得出结论。
在编译器实现方面,clang和gcc似乎一致接受所有定义,而MSVC的表现有所不同,且近期发生了行为变化:
| 函数 | gcc 12.2 | clang 15.0.0 | MSVC 19.33 | MSVC Latest (19.34?) |
|---|---|---|---|---|
f1 | 接受 | 接受 | 接受 | 接受 |
f2 | 接受 | 接受 | 错误C2244:无法将函数定义与现有声明匹配 | 错误C2244:无法将函数定义与现有声明匹配 |
f3 | 接受 | 接受 | 错误C2244:无法将函数定义与现有声明匹配 | 错误C2244:无法将函数定义与现有声明匹配 |
f4 | 接受 | 接受 | 接受 | 错误C2065:未声明标识符'B' |
内容的提问来源于stack exchange,提问作者LtSten
相关产品推荐
相关产品推荐

