在这种情况下,为什么g++和clang会破坏名称空间抽象?
Why do g++ and clang break the namespace abstraction in this case?
下面编译:
struct str {};
namespace a
{
void foo(str s) {}
}
namespace b
{
void foo(str s) {}
void bar(str s) { foo(s); }
}
int main(int, char**)
{
return 0;
}
但这没有(随着结构定义移动到命名空间a)
namespace a
{
struct str {};
void foo(str s) {}
}
namespace b
{
void foo(a::str s) {}
void bar(a::str s) { foo(s); }
}
int main(int, char**)
{
return 0;
}
我得到的错误是
bad.cpp: In function ‘void b::bar(a::str)’:
bad.cpp:12: error: call of overloaded ‘foo(a::str&)’ is ambiguous
bad.cpp:10: note: candidates are: void b::foo(a::str)
bad.cpp:5: note: void a::foo(a::str)
由于a::foo不在作用域中,因此对foo的调用只能引用b::foo,这似乎是合理的预期。编译失败是否有很好的原因(如果有,是什么原因),或者是(两个主要编译器)实现中的缺陷?
这是因为名称查找,特别是参数依赖查找(ADL)的工作方式。当决定哪些函数可能是解析调用的候选函数时,编译器将首先在
中查找名称。- 发生函数调用的命名空间;
- 定义参数类型的命名空间。
如果在这些命名空间中没有找到具有该名称的函数,编译器将继续检查调用所在命名空间的父命名空间。
那么你的问题中的例子是怎么回事呢?
在第一种情况下,str
在全局名称空间中定义,并且那里没有称为foo()
的函数。但是,在调用发生的命名空间(b
)中有一个:因此编译器已经找到了一个有效的名称,名称查找停止,并开始重载解析。
但是,只有一个候选函数!所以这里的任务很简单:编译器调用b::foo()
。
另一方面,在第二种情况下,str
在a
名称空间中定义,当调用foo(s)
时,编译器将再次查看调用的名称空间(b
)和定义参数类型的名称空间(str
) -这次是a
。
相关文章:
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 命名空间中具有.h和.cpp文件的类
- 从父命名空间重载类型
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- 在命名空间中定义函数还是限定函数
- 无法创建抽象类的实例
- C++:对不存在的命名空间使用命名空间指令
- 如何定义一个纯抽象基类
- 通过继承类使用来自不同命名空间的运算符
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 使用命名空间时出现多个定义错误
- OpenGL相机和相机空间转型的困惑
- 用pybind11包装C++抽象类时出错
- CUDA内核和数学函数的显式命名空间
- 打印第二列时的2d字符矢量打印空间
- 嵌套的匿名命名空间
- CMakeLists.txt中的命名空间表示法
- 类是C++中的命名空间吗
- 在命名空间中使用全局命名空间中的函数
- 在这种情况下,为什么g++和clang会破坏名称空间抽象?