AnT*_*AnT 10 c++ gcc operator-overloading language-lawyer argument-dependent-lookup
考虑这个代码示例
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);
}
Run Code Online (Sandbox Code Playgroud)
代码无法在GCC和Clang中编译,因为常规查找和ADL都无法解析bar
来自的调用foo
.这是完全可以预期的,因为bar
调用的关联命名空间列表就是这样N
.不包括全局命名空间,找不到全局命名空间bar
.一切都应该如此.
但是,如果我将其更改为
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);
}
Run Code Online (Sandbox Code Playgroud)
它突然开始在GCC中成功编译.(同时,Clang拒绝两个版本的代码).
似乎在代码的第二个(基于运营商的)版本中,GCC也将全局命名空间视为ADL的关联命名空间.
如果在后一版本的代码中我将调用更改为
template <class T> void foo(const S<T> &v)
{
operator +(v.t);
}
Run Code Online (Sandbox Code Playgroud)
它将再次无法在GCC编译.因此,似乎特别针对运算符表达式表示法给出了某种特殊处理,而不是函数调用表示法.
这个行为标准呢?我似乎没有在文档的文本中找到它(搜索"关联命名空间"),虽然我依稀记得读到有关GCC这种特性的一些内容.
这是gcc bug 51577.第二个测试用例几乎就是你的代码示例.
对于在全局命名空间中查找的运算符查找,没有特殊规则.[over.match.oper]/3有:
非成员候选集是
operator@
根据通常的非限定函数调用([basic.lookup.argdep]中的名称查找规则)在表达式的上下文中进行非限定查找的结果,除了忽略所有成员函数.
非限定函数调用中通常的名称查找规则不包括全局命名空间:[basic.lookup.argdep]/2:
如果
T
是类类型(包括联合),则其关联的类是:类本身; 它所属的成员,如果有的话; 及其直接和间接基类.其关联的命名空间是其关联类的最内部封闭命名空间.
N::A
是一个类类型,它的关联类本身,其关联的命名空间是最内部的封闭命名空间,这是N
,而不是::
.