4

这编译:

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。编译失败是否有充分的理由(如果是,那是什么),还是(两个主要编译器的)实现中的缺陷?

4

1 回答 1

7

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

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

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


那么您问题的示例中发生了什么?

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

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

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

所以现在有两个名称匹配的函数来解析调用:输入重载解析!唉,这两个功能都一样好(完全匹配,不需要转换)。因此,调用是模棱两可的。

于 2013-04-07T00:50:17.760 回答