c++ - 表达式中运算符的 GCC 和 ADL
问题描述
考虑这个代码示例
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 都无法解析对bar
from的调用foo
。这是完全可以预料的,因为bar
call 的关联命名空间列表只是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 错误 51577。第二个测试用例几乎就是您的代码示例。
对于在全局命名空间中查找的运算符查找没有特殊规则。[over.match.oper]/3有:
非成员候选集是根据非
operator@
限定函数调用 ([basic.lookup.argdep]) 中名称查找的常用规则在表达式上下文中非限定查找的结果,但忽略所有成员函数。
非限定函数调用中名称查找的通常规则不包括全局命名空间:[basic.lookup.argdep]/2:
如果
T
是类类型(包括联合),其关联的类是:类本身;它所属的类别(如有的话);及其直接和间接基类。其关联的命名空间是其关联类的最内层封闭的命名空间。
N::A
是一个类类型,它的关联类是它自己,它的关联命名空间是最里面的封闭命名空间,它只是N
,不是::
。
推荐阅读
- ios - iOS 上 WebGL 着色器中的莫名行为
- c++ - C++ & SDL 为什么直接处理我的对象而不是使用指针有时会导致视觉问题?
- ios - 在多个 UICollectionViews 中显示电影列表中的详细视图
- redis - redis中如何表示product_id和产品属性数据
- javascript - 将下拉框选择附加到文本框
- c# - 返回多行
- matlab - 在 MATLAB GUI 中进行函数计算后隐藏工作区中的特定变量
- java - 将图形(绘制)添加到预先存在的 JPanel
- python - Python UDP使用sendmsg设置TTL [Errno 22]无效参数
- python-3.x - Python - 从特定文件夹/子文件夹 AWS S3 下载数据