考虑以下代码,其中类 A
有一个嵌套类型 B
使用包含尾随 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>();
}
我一直无法找到/理解关于是否:
- 尾随 requires 子句可以命名嵌套类型,而无需以类似于尾随返回类型的方式进行显式限定
f2
中的哪一个,f3
, 和f4
,如果有的话,应该被一个符合标准的实现所接受
我能在标准草案中找到的最接近的是 [temp.mem],
A member template of a class template that is defined outside of its class template definition shall be specified with a template-head equivalent to that of the class template followed by a template-head equivalent to that of the member template (13.7.6.1).
13.7.6.1 在第 7 段中引用 [temp.over.link],
Two function templates are equivalent if they are declared in the same scope, have the same name, have equivalent template-heads, and have return types, parameter lists, and trailing requires-clauses (if any) that are equivalent using the rules described above to compare expressions involving template parameters.
就 requires 子句本身而言,等效性似乎由
they both have requires-clauses and the corresponding constraint-expressions are equivalent.
在任何其他情况下,我希望 f1
中的所有形式的约束通过f4
是(正式地)等效,但我对标准还不够熟悉,无法为自己下结论。
在实现方面,clang 和 gcc 似乎始终接受所有定义,而 MSVC 不同,并且最近在行为上发生了变化:
f1
f2
f3
f4
最佳答案
我引用的是当前草案而不是 C++20 草案,因为对相关部分进行了重大修订,使它们更加清晰。
根据 [basic.scope.class]/1成员函数的(非 friend
)重新声明的 declarator-id 之后的所有内容都在类的范围内,因此应该能够查找 B
具有不合格的名称。尾随 requires-clause 出现在 declarator-id A::fX
之后.
不过我认为是因为模板参数T
用于约束表达式 sentence 1 of [temp.over.link]/2 apply 表示表达式 C<T, A::B>
和 C<T, B>
仅当在两个函数定义中使用它们满足 ODR 时它们才等价,但模板参数可以重命名。但是 ODR 不允许使用不同的 token 序列来命名 A::B
.
但由于这两个表达式在功能上仍然是等价的,这将使它们不匹配的情况不合式;不需要诊断 (IFNDR),这意味着 f2
和 f3
将是无效的,尽管不需要诊断。这是因为必须检查等价性以确定类外定义是否是已在类中声明的成员的重新声明。如果两个结构在功能上是等价的,但当等价会影响程序的语义时不等价,那么该程序就是 IFNDR。
我认为等价规则有时很难遵循,所以我的看法可能不正确。但似乎 MSVC 遵循类似的解释,我怀疑 'B': undeclared identifier
最新版本中的错误只是回归。其他编译器的行为也与此解释兼容。
关于c++ - 带有尾随 requires 子句的类外模板成员函数定义的允许形式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74565443/