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

Why do g++ and clang break the namespace abstraction in this case?

本文关键字:空间 抽象 这种情况下 为什么 g++ clang      更新时间:2023-10-16

下面编译:

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)的工作方式。当决定哪些函数可能是解析调用的候选函数时,编译器将首先在

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

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


那么你的问题中的例子是怎么回事呢?

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

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

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

所以现在有两个函数,它们具有匹配的名称来解析调用:输入重载解析!可惜,这两个函数都一样好(精确匹配,不需要转换)。因此,调用是二义性的。