C++的朋友函数隐藏了类函数?

Joh*_*nes 10 c++ friend friend-function

最小的例子:

class A
{
    friend void swap(A& first, A& second) {}
    void swap(A& other) {}
    void call_swap(A& other)
    {
        swap(*this, other);
    }
};

int main() { return 0; }
Run Code Online (Sandbox Code Playgroud)

g ++ 4.7说:

friend.cpp: In member function ‘void A::call_swap(A&)’:
friend.cpp:7:20: error: no matching function for call to ‘A::swap(A&, A&)’
friend.cpp:7:20: note: candidate is:
friend.cpp:4:7: note: void A::swap(A&)
friend.cpp:4:7: note:   candidate expects 1 argument, 2 provided
Run Code Online (Sandbox Code Playgroud)

退出第4行:

// void swap(A& other) {}
Run Code Online (Sandbox Code Playgroud)

......它工作正常.如果我想保留交换功能的两种变体,为什么以及如何解决这个问题?

use*_*500 8

我相信这是因为编译器试图在类中找到该函数.这应该是一个简单的改变,使其工作(它在Visual Studio 2012中工作):

class A; // this and the next line are not needed in VS2012, but
void swap(A& first, A& second); // will make the code compile in g++ and clang++

class A
{
    friend void swap(A& first, A& second) {}
    void swap(A& other) {}
    void call_swap(A& other)
    {
        ::swap(*this, other); // note the scope operator
    }
};

int main() { return 0; }
Run Code Online (Sandbox Code Playgroud)


Mik*_*our 7

为什么

在类中,在类中作用域的名称隐藏了周围命名空间中的名称; 所以朋友(其名称在命名空间中作用域,但不能直接在那里访问)被成员隐藏(在类中作用域)并且在这里不可用作潜在的重载.(更新:或者它可能比这更复杂,如评论中所述.范围和名称查找规则有点难以理解,特别是当涉及到朋友时).

如果我想保留交换功能的两种变体,如何解决这个问题?

没有完美的解决方案.如果函数都做同样的事情,那么只需使用其他成员函数中的成员.如果你在类定义之外声明了朋友,那么它可以作为::swap; 但是如果将类放在不同的命名空间中,这有点脆弱.(更新:或使用此答案建议的静态成员函数;我没有想到这一点).

  • 我不认为*scope*参数适用于此:[class.friend]/7"类中定义的友元函数位于定义它的类的(词法)范围内." 但是,使用非限定查找找到的类成员会根据[basic.lookup.argdep]/3隐藏使用ADL找到的任何名称. (4认同)
  • @DyP我几乎可以肯定所有这些意味着你在友元函数定义中属于类范围,而不是将友元函数添加到重载决策候选列表中.friend函数存在于外部作用域中,该成员是另一个类成员范围内的唯一函数. (2认同)

jxh*_*jxh 7

作为解决方法,您可以声明一个static版本swap.然后,您可以声明friend版本以调用static版本.

class A
{
public:
    friend void swap(A& first, A& second) { A::swap(first, second); }
private:
    static void swap(A& first, A& second) {}
    void swap(A& other) {}
    void call_swap(A& other)
    {
        swap(*this, other);
    }
};

int main () {
    A a, b;
    swap(a, b);
}
Run Code Online (Sandbox Code Playgroud)