13

最近我注意到成员函数在类中完全隐藏了具有相同名称的自由函数。我的意思是完全不考虑重载决议的每个具有相同名称的自由函数。我可以理解为什么它是这样完成的:

void f();

struct S
{
    void f();

    void g()
    {
        f(); // calls S::f instead of ::f
    }
};

在函数具有相同签名的情况下,它唯一自然的变量作用域工作方式相同。但是为什么要禁止自由函数具有不同签名的明确调用,如下所示:

void f();

struct S
{
    void f(int x);

    void g()
    {
        f(); // fails to compile attempting to call S::f, which has wrong signature
    }
};

我不是在问如何从类内部调用阴影自由函数。我想知道的是这个设计背后的基本原理。

4

3 回答 3

9

对于非限定名称查找,一次只考虑一个范围,如果在该范围内的搜索没有产生任何结果,则搜索下一个更高的范围。在您的情况下,仅S搜索 ' 范围。

但是为什么要禁止自由函数具有不同签名的明确调用,如下所示:

问题是名称查找只关心名称和标识符。它完全没有意识到您想要调用一个函数,它只看到一个标识符。如果您只使用auto x = f;,则会发生相同的名称查找,并且如果您这样想,那么您有很好的理由只希望在非常有限的范围内进行搜索。其他任何事情都会让用户感到惊讶。

于 2012-07-27T22:03:36.077 回答
3

有一个特殊的,非常令人惊讶的规则(但它不适用于您的示例)指出,一旦通过名称查找找到类成员名称,就不会搜索名称空间范围:

#include <string>

struct C {
    std::string s;

    explicit C (std::string);

    void swap (C& rhs) {
        swap (s, rhs.s); // error: swap is C::swap
    }   
};

void swap (C& lhs, C& rhs) {
    swap (lhs.s, rhs.s); // std::swap(string,string)
}

IMO,这太疯狂了。

但是为什么要禁止自由函数具有不同签名的明确调用,如下所示:

名称查找发生在重载解析之前:

  • 如果查找不明确,则不会进行重载解析。
  • 如果通过名称查找没有找到可行的函数,则不会尝试其他轮次查找。

规则足够复杂,在重载和名称查找之间没有“反馈”。我建议简化(例如删除成员隐藏命名空间范围名称规则,并删除不明确的名称查找)而不是复杂化。

于 2012-08-16T22:45:42.537 回答
2

我无法提供权威的答案(也许有人记得当时委员会的引述Design and Evolution of C++或实际上已经在委员会中),但我的第一个猜测是在你展示的情况下完全失败。很容易忘记在某个时间有多少东西在范围内。此外,重载解析可能非常复杂,并且可能存在默认参数和转换。因此,在这种情况下,我宁愿拥有最有限的范围,以始终确定到底调用了什么。

于 2012-07-27T21:50:17.837 回答