【问题标题】:Why do g++ and clang break the namespace abstraction in this case?为什么 g++ 和 clang 在这种情况下会破坏命名空间抽象?
【发布时间】:2013-04-07 00:44:15
【问题描述】:

这样编译:

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

【问题讨论】:

    标签: c++ namespaces g++ overloading clang


    【解决方案1】:

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

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

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


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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多