为什么g ++和clang在这种情况下会破坏名称空间抽象?

ajp*_*ajp 4 c++ overloading namespaces g++ clang

这编译:

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;
}
Run Code Online (Sandbox Code Playgroud)

但这没有(结构定义在命名空间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;
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误是

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)
Run Code Online (Sandbox Code Playgroud)

由于a :: foo不在范围内,因此对foo的调用只能引用b :: foo,这似乎是合理的.是否有充分的理由让编译失败(如果是这样,它是什么),或者是(两个主要编译器的)实现中的缺陷?

And*_*owl 7

这是因为名称查找,特别是Argument-Dependent Lookup(ADL)的工作方式.在决定哪些函数可能是解析您的调用的候选函数时,编译器将首先在以下位置查找名称:

  1. 发生函数调用的命名空间;
  2. 定义了参数类型的名称空间.

如果在这些名称空间中找不到具有该名称的函数,则编译器将继续检查进行调用的名称空间的父名称空间.


那你的问题的例子中发生了什么?

在第一种情况下,str全局命名空间中定义,并且没有在那里调用的函数foo().但是,命名空间中有一个调用发生(b):所以编译器找到了一个有效的名称,名称查找停止,重载解析开始.

但是,只有一个候选功能!所以这里的任务很简单:编译器调用b::foo().

另一方面,在第二种情况下,在命名空间中str定义a,并且在调用时foo(s),编译器将再次查看调用的命名空间(b)和命名空间(其中str定义了参数()的类型-这一次,a.

所以现在有两个具有匹配名称的函数来解析调用:输入重载决策!唉,这两个功能同样好(完全匹配,不需要转换).因此,呼叫是模糊的.