根据非成员 swap() 实现成员 swap()

Implementing member swap() in terms of non-member swap()

我正在实现一个具有与 std::array 类似界面的 class,它同时具有 member swap() and the non-member swap().

因为我想让我的 class 模仿标准容器,所以我想实现两种 swap()(非成员 swap() 是通过 ADL 实现的,因为专门std::swap() 是不允许的):

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

但是,我似乎无法从 class 内部调用非成员 swap(),因为它更喜欢成员 swap(),即使它只有一个范围。将其更改为 ::swap(*this, other) 也不起作用,因为 in-class 友元函数只能通过 ADL 找到。我如何从 class 中调用非成员 swap()

以下对我有效(打印两次 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);
}

问题在于成员函数 swap 的名称在 A::swap 的主体中隐藏了名称空间作用域 swapA::swapswap 的非限定名称查找永远不会找到命名空间范围 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);
    }
};

话虽这么说,但我不确定这对您到底有什么用。显而易见的解决方案是根据 A::swap 而不是相反的方式来实现命名空间范围 swap。就个人而言,我一开始就不会使用 swap 成员函数。 The typical way of swapping ab 只是 swap(a, b)

您可以先声明 class 和交换函数,然后在成员函数中使用全局命名空间说明符。

现在您可以在 class 之外自由定义交换函数了。

#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