Bernard
Bernard

Reputation: 5666

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

I'm implementing a class with a similar interface to std::array, which has both the member swap() and the non-member swap().

Since I want my class to mimic the standard containers, I would like to implement both kinds of swap() (the non-member swap() is implemented via ADL, since specializing std::swap() isn't permitted):

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

However, it seems like I can't call the non-member swap() from inside the class, because it prefers the member swap() even though it only has a single parameter. Changing it to ::swap(*this, other) doesn't work as well, because the in-class friend function is only findable via ADL. How might I call the non-member swap() from inside the class?

Upvotes: 3

Views: 773

Answers (3)

Michael Kenzel
Michael Kenzel

Reputation: 15941

The problem is that the name of the member function swap hides the namespace-scope swap in the body of A::swap. Unqualified name lookup for swap in A::swap will never find namespace-scope swap and, thus, namespace-scope swap will not be part of the overload set. One way to get around this would be to simply add a declaration for namespace-scope swap in the body of A::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);
    }
};

That being said, I'm not sure what this really does for you. The obvious solution is to just implement namespace-scope swap in terms of A::swap rather than the other way around. Personally, I would just not have a swap member function to begin with. The typical way of swapping aand b is to just swap(a, b)

Upvotes: 4

Allan Cameron
Allan Cameron

Reputation: 173898

You can declare your class and your swap function first, then use the global namespace specifier within your member function.

Now you are free to define your swap function outside the 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;
}

Outputs:

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

Upvotes: 0

n314159
n314159

Reputation: 5085

The following works for me (it prints blah twice)

#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);
}

Upvotes: 2

Related Questions