How to Provide a Swap Function For My Class

how to provide a swap function for my class?

  1. is the proper use of swap. Write it this way when you write "library" code and want to enable ADL (argument-dependent lookup) on swap. Also, this has nothing to do with SFINAE.
// some algorithm in your code
template<class T>
void foo(T& lhs, T& rhs) {
using std::swap; // enable 'std::swap' to be found
// if no other 'swap' is found through ADL
// some code ...
swap(lhs, rhs); // unqualified call, uses ADL and finds a fitting 'swap'
// or falls back on 'std::swap'
// more code ...
}

  1. Here is the proper way to provide a swap function for your class:
namespace Foo {

class Bar{}; // dummy

void swap(Bar& lhs, Bar& rhs) {
// ...
}

}

If swap is now used as shown in 1), your function will be found. Also, you may make that function a friend if you absolutely need to, or provide a member swap that is called by the free function:

// version 1
class Bar{
public:
friend void swap(Bar& lhs, Bar& rhs) {
// ....
}
};

// version 2
class Bar{
public:
void swap(Bar& other) {
// ...
}
};

void swap(Bar& lhs, Bar& rhs) {
lhs.swap(rhs);
}

...

  1. You mean an explicit specialization. Partial is still something else and also not possible for functions, only structs / classes. As such, since you can't specialize std::swap for template classes, you have to provide a free function in your namespace. Not a bad thing, if I may say so. Now, an explicit specialization is also possible, but generally you do not want to specialize a function template:
namespace std
{ // only allowed to extend namespace std with specializations

template<> // specialization
void swap<Bar>(Bar& lhs, Bar& rhs) noexcept {
// ...
}

}

  1. No, as 1) is distinct from 2) and 3). Also, having both 2) and 3) will lead to always having 2) picked, because it fits better.

How to provide swap() for a class in the global namespace?

In general, no library should use the global namespace, only the main application. And even that rarely, who knows when you will make part of it its own library?

Aside from that, the global scope :: is a namespace like any other, thus if you define a type there, the associated free functions belong there too.

Otherwise, argument-dependent lookup cannot find them.

When to provide custom swap function in C++?

You should follow the rule of 0.

Non-resource managing classes should have default move/copy/assign/destruction.

Resource managing classes should be only concerned with managing resources.

Your code does not manage resources. Everything copy/move wise should be defaulted.

swap is a special case of move. In the case you are a resource managing type, you may want to also write it. However, like most things, it is an optimization, and you shoud only do such optimizations if you have proven it has performance impact.

An example of when it might have performance impact is if you have a never-empty resource-owning type and that resource isn't free, so creating a temporary object has unavoidable costs. std::swap by default moves through a throw-away object. A custom swap could avoid this.

Or, a type that is a large buffer of cheap to move elements; creating that large buffer could have real costs.

Otherwise, don't do it. And test if you do it that it helps. Custom swap is a optimization of move for a particular case.

Swap function for user-defined class never instantiated?

friend void swap(Wrapper& a, Wrapper& b);

declares a non-template function swap that happens to take Wrapper<T>& arguments. This doesn't match with your template function swap<T>.

One simple fix is to declare the friend as the template function.

template <typename U>
friend void swap(Wrapper<U>&a, Wrapper<U>& b);

The drawback there is you've friended a little more than you wanted: every swap instantiation is a friend of every Wrapper<T>, not just the correct Wrapper<T> class.

A more correct way involves declaring the template function before the class:

template <class T> class Wrapper;
template <class T>
void swap(Wrapper<T>&, Wrapper<T>&);

template <class T>
class Wrapper
{
friend void swap<>(Wrapper&, Wrapper&);
// ...

How to get a generalized Swap-function?

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';
}

What's a reason to provide a swap() for the user defined type?

The global std::swap requires creation of a temporary. A custom class based swap will be aware of the internals of the class, and can do the swap more efficiently, without having to create another variable of the class type.

In your case, that internal swap can just swap the internal socket_id values, without having to do all that extra stuff in the move constructor and move assignment operator (which will be called twice).

I want to swap two numbers by using another class with a swap method and not the general swap function which is commonly available

You are essentially swapping the two numbers twice, and therefore not swapping them at all:

swapper s = new swapper(a[j],a[j+1]); // this assigns a[j] to s.x and a[j+1] to s.y
s.swap(); // this swaps s.x and s.y
a[j] = s.y; // this assigns the original value of s.x (a[j]) to a[j]
a[j+1] = s.x; // this assigns the original value of s.y (a[j+1]) to a[j+1]

In order for the swapping to work as expected, change it to:

swapper s = new swapper(a[j],a[j+1]); 
s.swap();
a[j] = s.x;
a[j+1] = s.y;

How to implement function with one argument that swaps private content of objects

Here is a demonstrative program that shows how a member function swap can be defined.

#include <iostream>
#include <utility>

class A
{
private:
int x;
public:
explicit A( int x = 0 ) : x( x ) {}

void swap( A &a ) noexcept
{
int tmp = std::move( a.x );
a.x = std::move( this->x );
this->x = std::move( tmp );
}

void swap( A &&a ) noexcept
{
int tmp = std::move( a.x );
a.x = std::move( this->x );
this->x = std::move( tmp );
}


const int & getX() const { return x; }
};

int main()
{
A a1( 10 );
A a2( 20 );

std::cout << "a1.x = " << a1.getX() << '\n';
std::cout << "a2.x = " << a2.getX() << '\n';

a1.swap( a2 );

std::cout << "a1.x = " << a1.getX() << '\n';
std::cout << "a2.x = " << a2.getX() << '\n';

a1.swap( A( 30 ) );

std::cout << "a1.x = " << a1.getX() << '\n';

return 0;
}

The program output is

a1.x = 10
a2.x = 20
a1.x = 20
a2.x = 10
a1.x = 30

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

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)

How to add std::swap for my template class?

You are not allowed to overload functions in the std-namespace.

Declare swap as a free function, overloaded in the same namespace as your class C:

 template<class T>
void swap(C<T>& x, C<T>& y) { x.swap(y); }

The right way to swap is to import std::swap and use a non-qualified version (which is retreieved via namespace-based Koenig lookup):

 template<class T>
void dostuff(T x, T y) {
...
using std::swap;
swap(x,y);
...
}

That will use C::swap if x and are C, and std::swap for types that do not have their own swap.

(The import of std::swap like above is only necessary in template functions where the type is not known. If you know you have a C, then you can use x.swap(y) right away w/o problems.)



Related Topics



Leave a reply



Submit