gcc和clang在运算符重载解析期间隐式实例化模板参数 [英] gcc and clang implicitly instantiate template arguments during operator overload resolution

查看:162
本文介绍了gcc和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
}

隐藏。由于 u.operator =(v)编译,但 u = v; 后面的表达式编译器必须隐式实例化 D< A> - 但我不明白为什么实例化是必需的。

Demo. Since u.operator=(v) compiles but u = v; doesn't, somewhere during the overload resolution for the latter expression the compiler must have implicitly instantiated D<A> - but I don't see why that instantiation is required.

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

To make things more interesting, this code compiles:

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);
}

演示

这里发生了什么?为什么 u = v; 导致隐式实例化 D - 一种在主体中没有使用的类型

What's going on here? Why does u = v; cause the implicit instantiation of D<A> - a type that's nowhere used in the body of B's definition - in the first case but not the second?

推荐答案

问题的整个重点是 ADL 踢:

N3797 - [basic.lookup.argdep]

N3797 - [basic.lookup.argdep]


当函数调用中的postfix-expression是一个非限定id,在通常的非限定查找(3.4.1)期间可以搜索不被认为是
的其他命名空间,并且在这些命名空间中,命名空间范围
friend函数或函数模板声明

When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched, and in those namespaces, namespace-scope friend function or function template declarations (11.3) not otherwise visible may be found.



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

  • If T is a class type [..] its associated classes are: ... furthemore if T is a class template specialization its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters

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

D< A>

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

Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3), the class template specialization is implicitly instantiated [...] when the completeness of the class type affects the semantics of the program


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

类型 D 的完整性不影响该程序的所有语义,然而[basic.lookup.argdep] / 4说:

When considering an associated namespace, the lookup is the same as the lookup performed when the associated namespace is used as a qualifier (3.4.3.2) except that:


当考虑一个关联的命名空间时,查找与当相关命名空间用作限定符时执行的查找相同(3.4.3.2)
除了:

[...] Any namespace-scope friend functions or friend function templates declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup (11.3)

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

i.e. the completeness of the class type actually affects friends declarations -> the completeness of the class type therefore affects the semantics of the program. That is also the reason why your second sample works.

ie类类型的完整性实际影响朋友声明 - >类类型的完整性因此影响程序的语义。
这也是您的第二个示例工作原因。

TL;DR D<A> is instantiated.

TL; DR D&

The last interesting point regards why ADL starts in the first place for

最后一个有趣的点是为什么ADL从

u = v; // Triggers ADL u.operator=(v); // Doesn't trigger ADL

§13.3.1.2/2 dictates that there can be no non-member operator= (other than the built-in ones). Join this to [over.match.oper]/2:

§13.3.1.2/ 2表示, member operator = (内置的除外)。加入这个到[over.match.oper] / 2:

The set of non-member candidates is the result of the unqualified lookup of operator@ in the context of the expression according to the usual rules for name lookup in unqualified function calls (3.4.2) except that all member functions are ignored.


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

and the logical conclusion is: there's no point in performing the ADL lookup if there's no non-member form in table 11. However [temp.inst]p7 relaxes this:

,逻辑结论是:如果表11中没有非成员表单,执行ADL查找没有意义。但是[temp.inst] p7放松了这一点: / p>

If the overload resolution process can determine the correct function to call without instantiating a class template definition, it is unspecified whether that instantiation actually takes place.


如果重载解析过程可以确定正确的函数而不实例化类模板定义,则不会指定实例化是否实际发生。

and that's the reason why clang triggered the entire ADL -> implicit instantiation process in the first place.

这就是clang触发整个 ADL - >隐式实例化过程。

Starting from r218330 (at the time of writing this, it has been committed a few minutes ago) this behavior was changed not to perform ADL for operator= at all.

r218330 (在写这篇文章的时候,已经提交了几分钟前)这个行为更改为不执行ADL

References

  • r218330
  • clang sources / Sema module
  • cfe-dev
  • N3797

感谢Richard Smith和David Blaikie帮我找出这个。

Thanks to Richard Smith and David Blaikie for helping me figuring this out.

这篇关于gcc和clang在运算符重载解析期间隐式实例化模板参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆