简体   繁体   English

表达式中的运算符的GCC和ADL

[英]GCC and ADL for operators in expressions

Consider this code sample 考虑这个代码示例

template <typename T> struct S { T t; };

template <class T> void foo(const S<T> &v)
{
  bar(v.t);
}

namespace N
{
  struct A {};
} 

void bar(const N::A &a) {}

int main()
{
  S<N::A> a;
  foo(a);    
}

The code fails to compile in GCC and Clang, since neither regular lookup nor ADL can resolve the call to bar from foo . 代码无法在GCC和Clang中编译,因为常规查找和ADL都无法解析来自foo bar调用。 This is perfectly expected, since the list of associated namespaces for bar call is just N . 这是完全可以预料到的,因为bar调用的关联命名空间列表只是N Global namespace is not included, global bar is not found. 不包括全局命名空间,找不到全局bar All as it should be. 一切都应该如此。

However, if I change it to 但是,如果我将其更改为

template <typename T> struct S { T t; };

template <class T> void foo(const S<T> &v)
{
  +v.t;
}

namespace N
{
  struct A {};
} 

void operator +(const N::A& a) {}

int main()
{
  S<N::A> a;
  foo(a);    
}

It suddenly begins to compile successfully in GCC. 它突然开始在GCC中成功编译。 (Meanwhile, Clang rejects both versions of the code). (同时,Clang拒绝两个版本的代码)。

It appears that in the second (operator-based) version of the code GCC considers global namespace as an associated namespace for ADL as well. 似乎在代码的第二个(基于运营商的)版本中,GCC也将全局命名空间视为ADL的关联命名空间。

If in the latter version of the code I change the call to 如果在后一版本的代码中我将调用更改为

template <class T> void foo(const S<T> &v)
{
  operator +(v.t);
}

It will again fail to compile in GCC. 它将再次无法在GCC编译。 So, it appears some sort of special treatment is given to operators-in-expressions notation specifically, but not to function-call notation. 因此,似乎特别针对运算符表达式表示法给出了某种特殊处理,而不是函数调用表示法。

It this behavior standard? 这个行为标准呢? I don't seem to find it in the text of the document (searching for "associated namespace"), although I do vaguely remember reading something about this peculiarity of GCC. 我似乎没有在文档的文本中找到它(搜索“关联命名空间”),虽然我依稀记得读到有关GCC这种特性的一些内容。

This is gcc bug 51577 . 这是gcc bug 51577 The second test case there is pretty much exactly your code example. 第二个测试用例几乎就是你的代码示例。

There is no special rule for operator lookup that would look in the global namespace. 对于在全局命名空间中查找的运算符查找,没有特殊规则。 [over.match.oper]/3 has: [over.match.oper] / 3有:

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 ([basic.lookup.argdep]) except that all member functions are ignored. 根据通常的非限定函数调用([basic.lookup.argdep]中的名称查找规则),非成员候选集合是表达式上下文中operator@的非限定查找的结果,除了所有成员函数都是忽略。

The usual rules for name lookup in unqualified function calls does not include the global namespace: [basic.lookup.argdep]/2 : 非限定函数调用中通常的名称查找规则不包括全局命名空间: [basic.lookup.argdep] / 2

If T is a class type (including unions), its associated classes are: the class itself; 如果T是类类型(包括联合),则其关联的类是:类本身; the class of which it is a member, if any; 它所属的成员,如果有的话; and its direct and indirect base classes. 及其直接和间接基类。 Its associated namespaces are the innermost enclosing namespaces of its associated classes. 其关联的命名空间是其关联类的最内部封闭命名空间。

N::A is a class type, its associated class is itself, its associated namespaces are the innermost enclosing namespaces, which is just N , not :: . N::A是一个类类型,它的关联类本身,其关联的命名空间是最内层的封闭命名空间,它只是N ,而不是::

This bug report seem to be related Bug 70099 . 这个错误报告似乎与Bug 70099有关。 The namespace of the operator is not considered in the lookup. 查找中不考虑运算符的名称空间。

The operator is a dependent name [temp.dep]/1.3 : 运算符是从属名称[temp.dep]/1.3

If an operand of an operator is a type-dependent expression, the operator also denotes a dependent name. 如果运算符的操作数是类型相关的表达式,则运算符也表示从属名称。 Such names are unbound and are looked up at the point of the template instantiation (17.6.4.1) in both the context of the template definition and the context of the point of instantiation 这些名称是未绑定的,并且在模板定义的上下文和实例化点的上下文中都会查看模板实例化(17.6.4.1)

and by [temp.dep.res] 并通过[temp.dep.res]

In resolving dependent names, names from the following sources are considered: 1. Declarations that are visible at the point of definition of the template. 在解析依赖名称时,将考虑以下来源的名称:1。在模板定义时可见的声明。 2. Declarations from namespaces associated with the types of the function arguments both from the instantiation context (17.6.4.1) and from the definition context. 2.来自名称空间的声明,这些名称空间与实例化上下文(17.6.4.1)和定义上下文中的函数参数的类型相关联。

and the declaration of the operator is in neither of the contexts nor in the associated namespaces of N::A . 并且运算符的声明既不在上下文中,也不在N::A的相关名称空间中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM