gcc和clang在运算符重载解析期间隐式实例化模板参数

T.C*_*.C. 32 c++ gcc templates clang

考虑以下代码:

struct A; // incomplete type

template<class T>
struct D { T d; };

template <class T>
struct B { int * p = nullptr; };

int main() {
    B<D<A>> u, v;
    u = v;  // doesn't compile; complain that D<A>::d has incomplete type
    u.operator=(v); // compiles
}
Run Code Online (Sandbox Code Playgroud)

演示.由于u.operator=(v)编译但u = v;没有,在后一个表达式的重载解析期间,编译器必须已经隐式实例化D<A>- 但我不明白为什么需要实例化.

为了使事情更有趣,这段代码编译:

struct A; // incomplete type

template<class T>
struct D; // undefined

template <class T>
struct B { int * p = nullptr; };

int main() {
    B<D<A>> u, v;
    u = v;
    u.operator=(v);
}
Run Code Online (Sandbox Code Playgroud)

演示.

这里发生了什么?为什么u = v;导致隐式实例化D<A>- 一种在B定义体中没有使用的类型- 在第一种情况下而不是第二种情况?

Mar*_* A. 19

问题的全部内容是ADL踢:

N3797 - [basic.lookup.argdep]

当函数调用(5.2.2)中的postfix-expression是非限定id时,可以搜索在通常的非限定查找(3.4.1)期间未考虑的其他命名空间,并且在这些命名空间中,命名空间范围的朋友函数或函数可以找到不可见的模板声明(11.3).

以下:

对于函数调用中的每个参数类型T,存在一组零个或多个关联的命名空间以及要考虑的一组零个或多个关联的类.[...]命名空间和类的集合按以下方式确定:

  • 如果T是类类型[..],则其关联的类是:...如果T是类模板特化,则其关联的名称空间和类还包括:与模板类型提供的模板参数类型相关联的名称空间和类参数

D<A> 是一个关联的类,因此在列表等待轮到它.

现在为有趣的部分[temp.inst]/1

除非已经显式实例化了类模板特化(14.7.2)或显式专用(14.7.3),否则当类类型的完整性影响程序的语义时,类模板特化将被隐式实例化[...]

可以认为该类型的完整性D<A>并不影响该程序的所有语义,但[basic.lookup.argdep]/4表示:

在考虑关联的命名空间时,查找与关联命名空间用作限定符时执行的查找相同(3.4.3.2),但以下情况除外:

[...]在关联类中声明的任何命名空间范围的朋友函数或朋友函数模板在其各自的命名空间中都是可见的,即使它们在普通查找期间不可见(11.3)

即类类型的完整性实际上影响了朋友声明 - >类类型的完整性因此影响了程序的语义.这也是你的第二个样本有效的原因.

TL; DR D<A>被实例化.

最后一个有趣的观点是为什么ADL首先开始

u = v; // Triggers ADL
u.operator=(v); // Doesn't trigger ADL
Run Code Online (Sandbox Code Playgroud)

§13.3.1.2/ 2规定不能有非成员operator=(除内置成员外).加入[over.match.oper]/2:

根据通常的非限定函数调用(3.4.2)中的名称查找规则,非成员候选集合是表达式上下文中operator @的非限定查找的结果,除了忽略所有成员函数.

逻辑结论是:如果表11中没有非成员形式,则执行ADL查找没有意义.但[temp.inst] p7放宽了这个:

如果重载解析过程可以在不实例化类模板定义的情况下确定要调用的正确函数,则未指定该实例化是否实际发生.

这就是为什么clang首先触发了整个ADL -> implicit instantiation过程的原因.

r218330开始(在撰写本文时,它已在几分钟前提交),此行为已更改为根本不执行ADL operator=.


参考

感谢理查德史密斯和大卫布莱基帮助我解决这个问题.

  • 啊哈,所以我走在了正确的轨道上.感谢你比我更执着,并与clang开发人员一起检查. (2认同)