slashmais
slashmais

Reputation: 7155

How to get a generalized Swap-function?

Using the example for std::swap on cppreference I tried the following SWAP-template:

#include <algorithm>
#include <iostream>

namespace Ns
{
class A
{
    int id{};
 
    friend void swap(A& lhs, A& rhs)
    {
        std::cout << "swap(" << lhs << ", " << rhs << ")\n";
        std::swap(lhs.id, rhs.id);
    }
 
    friend std::ostream& operator<< (std::ostream& os, A const& a)
    {
        return os << "A::id=" << a.id;
    }
 
public:
    A(int i) : id{i} { }
    A(A const&) = delete;
    A& operator = (A const&) = delete;
};
}

template<typename T> void SWAP(T &l, T &r)
{
    try { std::swap(l, r); }
    catch(...) { swap(l, r); }
}

int main()
{
    std::cout << "\n======================\n";
    int a = 5, b = 3;
    std::cout << "before: " << a << ' ' << b << '\n';
    std::swap(a,b);
    std::cout << "after:  " << a << ' ' << b << '\n';
    std::cout << "\n=========\n";
    Ns::A p{6}, q{9};
    std::cout << "before: " << p << ' ' << q << '\n';
    //  std::swap(p, q);  // error, type requirements are not satisfied
    swap(p, q);  // OK, ADL finds the appropriate friend `swap`
    std::cout << "after: " << p << ' ' << q << '\n';

    std::cout << "\n======================\n";
    std::cout << "before: " << a << ' ' << b << '\n';
    SWAP(a,b);
    std::cout << "after:  " << a << ' ' << b << '\n';
    std::cout << "\n=========\n";
    std::cout << "before: " << p << ' ' << q << '\n';
    SWAP(p, q);
    std::cout << "after: " << p << ' ' << q << '\n';
}

to handle the 'friend' swap-function in the namespace; to have just a single SWAP function to call that will handle all cases.

The compiler-error: swap was not declared in this scope

Why does calling swap() for the namespace work in main but not in the template?
and is there a way to have a generalized 'SWAP'-function to handle all such cases?

(edit)

Thanks to @rici the following change to the template works:

template<typename T> void SWAP(T &l, T &r)
{
    using namespace std;
    swap(l, r);
}

I would still appreciate an ELI5 for the first part of my question: what/how/why does this work ...

Upvotes: 1

Views: 159

Answers (1)

A M
A M

Reputation: 15267

There are 2 problems.

Please first read the definition of 'std::swap' here.

You will read the requirements for the type.

  1. You are using exceptions in your swap function. Remove that.
  2. From the description, you can see that your type must be

Type requirements

  • T must meet the requirements of MoveAssignable and MoveConstructible.
  • T2 must meet the requirements of Swappable.

You defined (deleted) a constructor and assign operator. With that the compiler will not create the standard constructors/assign operators for you. Please read about the rule of 5.

Your class is no longer MoveAssignable and MoveConstructible.

Simply remove the deleted operator and constructor.

Like the below. Then it will compile.

#include <algorithm>
#include <iostream>

namespace Ns
{
    class A
    {
        int id{};

        friend void swap(A& lhs, A& rhs)
        {
            std::cout << "swap(" << lhs << ", " << rhs << ")\n";
            std::swap(lhs.id, rhs.id);
        }

        friend std::ostream& operator<< (std::ostream& os, A const& a)
        {
            return os << "A::id=" << a.id;
        }

    public:
        A(int i) : id{ i } { }
        //A(A const&) = delete;
        //A& operator = (A const&) = delete;
    };
}

template<typename T> 
void SWAP(T& l, T& r)
{
    std::swap(l, r);
}

int main()
{
    std::cout << "\n======================\n";
    int a = 5, b = 3;
    std::cout << "before: " << a << ' ' << b << '\n';
    std::swap(a, b);
    std::cout << "after:  " << a << ' ' << b << '\n';
    std::cout << "\n=========\n";
    Ns::A p{ 6 }, q{ 9 };
    std::cout << "before: " << p << ' ' << q << '\n';
    //  std::swap(p, q);  // error, type requirements are not satisfied
    swap(p, q);  // OK, ADL finds the appropriate friend `swap`
    std::cout << "after: " << p << ' ' << q << '\n';

    std::cout << "\n======================\n";
    std::cout << "before: " << a << ' ' << b << '\n';
    SWAP(a, b);
    std::cout << "after:  " << a << ' ' << b << '\n';
    std::cout << "\n=========\n";
    std::cout << "before: " << p << ' ' << q << '\n';
    SWAP(p, q);
    std::cout << "after: " << p << ' ' << q << '\n';
}

Upvotes: 1

Related Questions