[英]GCC and ADL for operators in expressions
考虑这个代码示例
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);
}
代码无法在GCC和Clang中编译,因为常规查找和ADL都无法解析来自foo
bar
调用。 这是完全可以预料到的,因为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);
}
它突然开始在GCC中成功编译。 (同时,Clang拒绝两个版本的代码)。
似乎在代码的第二个(基于运营商的)版本中,GCC也将全局命名空间视为ADL的关联命名空间。
如果在后一版本的代码中我将调用更改为
template <class T> void foo(const S<T> &v)
{
operator +(v.t);
}
它将再次无法在GCC编译。 因此,似乎特别针对运算符表达式表示法给出了某种特殊处理,而不是函数调用表示法。
这个行为标准呢? 我似乎没有在文档的文本中找到它(搜索“关联命名空间”),虽然我依稀记得读到有关GCC这种特性的一些内容。
这是gcc bug 51577 。 第二个测试用例几乎就是你的代码示例。
对于在全局命名空间中查找的运算符查找,没有特殊规则。 [over.match.oper] / 3有:
根据通常的非限定函数调用([basic.lookup.argdep]中的名称查找规则),非成员候选集合是表达式上下文中
operator@
的非限定查找的结果,除了所有成员函数都是忽略。
非限定函数调用中通常的名称查找规则不包括全局命名空间: [basic.lookup.argdep] / 2 :
如果
T
是类类型(包括联合),则其关联的类是:类本身; 它所属的成员,如果有的话; 及其直接和间接基类。 其关联的命名空间是其关联类的最内部封闭命名空间。
N::A
是一个类类型,它的关联类本身,其关联的命名空间是最内层的封闭命名空间,它只是N
,而不是::
。
这个错误报告似乎与Bug 70099有关。 查找中不考虑运算符的名称空间。
运算符是从属名称[temp.dep]/1.3
:
如果运算符的操作数是类型相关的表达式,则运算符也表示从属名称。 这些名称是未绑定的,并且在模板定义的上下文和实例化点的上下文中都会查看模板实例化(17.6.4.1)
并通过[temp.dep.res]
在解析依赖名称时,将考虑以下来源的名称:1。在模板定义时可见的声明。 2.来自名称空间的声明,这些名称空间与实例化上下文(17.6.4.1)和定义上下文中的函数参数的类型相关联。
并且运算符的声明既不在上下文中,也不在N::A
的相关名称空间中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.