使用非成员函数swap()实现成员函数swap()的功能

3

我正在实现一个类,其接口与 std::array 相似,该类具有成员函数 swap() 和非成员函数 swap()

由于我希望我的类模仿标准容器,因此我想要实现这两种类型的 swap() (通过 ADL 实现非成员函数 swap(),因为不允许特化 std::swap()):

class A {
    public:
        friend void swap(A& a, A& b) { /* swap the stuff */ }
        void swap(A& other) { swap(*this, other); }
};

然而,似乎我无法从类内部调用非成员的swap(),因为它更倾向于成员的swap(),即使它只有一个参数。将其更改为::swap(*this, other)也不起作用,因为在类内友元函数只能通过ADL找到。我该如何从类内调用非成员swap()呢?

5
为什么不使用成员函数swap来实现非成员函数swap - Evg
@Evg 我可以这样做,但是非成员的swap对称性看起来更好。 - Bernard
你为什么想在友元函数 void swap(A& a, A& b) 中添加交换的实现呢?它应该属于一个成员函数,比如 void swap(A& other),然后 void swap(A& a, A& b) 可以调用这个成员函数。 - t.niese
1
此外,如果您按照正确的方式实现非成员函数(使用成员函数来实现),则不需要使非成员函数成为该类的友元。您显然是在制造问题... - Phil1970
@Phil1970,你有参考资料说明使用成员函数实现非成员函数是正确的方式吗? - Bernard
是的,你只需要看一下标准库中专家们是如何实现的。在MSVC中,std::vectorstd::array以及可能大多数其他容器都是这样实现的。而且,你会发现用这种方式实现很困难,而另一种方式却很容易。我没有具体的参考资料,但这已经成为了共识。 - Phil1970
3个回答

4
该问题在于成员函数swap的名称在A::swap中覆盖了命名空间范围内的swap。在A::swap中未经修饰的名称查找swap将永远不会找到命名空间范围内的swap,因此命名空间范围内的swap将不会成为重载集的一部分。解决这个问题的方法之一是在A::swap的主体中添加一个命名空间范围内的swap声明。
class A
{
public:
    friend void swap(A& a, A& b) { /* swap the stuff */ }

    void swap(A& other)
    {
        void swap(A& a, A& b);
        swap(*this, other);
    }
};

话虽如此,我不确定这对你确实有什么帮助。明显的解决方案是实现基于名称空间的swap而非另一种方式中的A::swap。从个人角度来看,我首先不会有swap成员函数。交换ab典型方法就是使用swap(a, b)


如果你的设计鼓励块级作用域函数声明,那么你的做法是错误的。 - Davis Herring

2
以下内容对我有效(它会打印两次blah)。
#include <utility>
#include <iostream>

class A {
    public:
        friend void swap(A& a, A& b) { std::cout << "blah\n";/* swap the stuff */ }
        void swap(A& other) {  using std::swap; swap(*this, other); }
};

int main() {
    A a, b;
    swap(a,b);
    a.swap(b);
}

可能值得说明一下为什么要请求(不可定制的!)std::swap 找到隐藏的友元。 - Davis Herring

0
你可以先声明你的类和交换函数,然后在成员函数中使用全局命名空间限定符。
现在你可以自由地在类外定义你的交换函数。
#include <algorithm>
#include <iostream>

class A;
void swap(A& a, A& b);

class A {
    int the_stuff;

  public:
    A(int a): the_stuff(a) {}
    friend void swap(A& a, A& b);
    void print_stuff(){std::cout << "A's stuff is " << the_stuff << std::endl;}
    void swap(A& other){
      ::swap(*this, other);
      std::cout << "Member swap" << std::endl;}
};

void swap(A& a, A& b)
{
  std::swap(a.the_stuff, b.the_stuff);
  std::cout << "Friend swap" << std::endl;
}

int main()
{
  A a = 1, b = 2;
  a.print_stuff();
  swap(a, b);
  a.print_stuff();
  return 0;
}

输出:

//> A's stuff is 1
//> Friend swap
//> A's stuff is 2

请注意,问题中的友元swap可以受益于成为隐藏友元 - Evg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接