Providing swap() for a C++ template class breaks std::swap()?
I was trying to implement the copy-and-swap idiom in my custom Matrix class, and I ran into some trouble with the implementation of swap() in the way suggested in the linked-to question:
(The compiler I used is the one from MS VS2010 IDE, dialect is good old-fashioned C++03.)
// matrix.h
namespace my_space
{
template<typename T> class Matrix
{
public:
/* ... */
friend void swap(Matrix<T> &first, Matrix<T> &second)
{
using std::swap;
swap(first.width_, second.width_);
swap(first.height_, second.height_);
swap(first.data_, second.data_);
}
};
} // namespace
Now I have trouble reaching regular std::swap() in the code for functions residing in this namespace:
// some_code.cpp:
#include "matrix.h"
#include <algorithm>
using namespace my_space;
using namespace std;
// SomeClass is part of my_space!
void SomeClass::some_function()
{
int a = 3, b = 7;
swap(a,b); // I wan't std::swap!
}
Unfortunately, for some reason, my_space::swap()
for Matrix seems to alias all other calls to std::swap()
, and I've no idea why since the arguments don't fit and ADL should favor std::swap
:
1>f:srcsome_code.cpp(653): error C3767: 'swap': candidate function(s) not accessible
1> could be the friend function at 'f:srcmatrix.h(63)' : 'swap' [may be found via argument-dependent lookup]
(The error repeats 10 times for every line where I'm trying to use std::swap
)
Does my_space::swap()
always overrule std::swap()
in my_space
, even if the arguments don't fit? It's not as if std::swap()
is not visible, and it worked OK before my_space::swap()
was created.
The approach taken by STL containers uses a member function and then overload the static function. For example:
template<class T, class Alloc=std::allocator<T> >
class vector
{
T *data;
size_t n;
size_t max_n;
public:
void swap(vector<T, Alloc> &other)
{
swap(this->data, other.data);
swap(this->n, other.n);
swap(this->max_n, other.max_n);
}
};
template<class T, class A>
void swap(vector<T, A> &lhs, vector<T, A> &rhs)
{
lhs.swap(rhs);
}
In the suggested Matrix class, simply take the same approach...
namespace my_space
{
template<typename T>
class Matrix
{
unsigned width_;
unsigned height_;
std::vector<T> data_;
public:
void swap(Matrix<T> &other)
{
std::swap(this->width_, other.width_);
std::swap(this->height_, other.height_);
std::swap(this->data_, other.data_); // calls this->data_.swap(other.data_);
}
};
}
namespace std
{
template<typename T>
void swap(my_space::Matrix<T> &lhs, my_space::Matrix<T> &rhs)
{
lhs.swap(rhs);
}
}
Include the following line in Matrix
:
template<typename U> friend void swap(Matrix<U> &first, Matrix<U> &second);
and define the swap
outside of the class. The reason you are getting the error function template has already been defined
, is because each instantiation of Matrix<unsigned short>
and Matrix<char>
will contain the same defintion of your swap function since you defined the friend function inside of the Matrix
template.
The following builds cleanly for me with VC++ 2010 SP1:
Matrix.h:
#pragma once
#include <algorithm>
#include <vector>
namespace my_space
{
template<typename T>
class Matrix
{
public:
Matrix(unsigned const w, unsigned const h)
: width_(w), height_(h), data_(w * h)
{ }
private:
unsigned width_;
unsigned height_;
std::vector<T> data_;
friend void swap(Matrix& lhs, Matrix& rhs)
{
using std::swap;
swap(lhs.width_, rhs.width_);
swap(lhs.height_, rhs.height_);
swap(lhs.data_, rhs.data_);
}
};
}
.cpp:
#include "Matrix.h"
int main()
{
using namespace my_space;
using std::swap;
int a(0), b(1);
swap(a, b);
Matrix<int> c(2, 3), d(4, 5);
swap(c, d);
Matrix<short> e(6, 7), f(8, 9);
swap(e, f);
}
Since you didn't post an SSCCE (hint, hint), it's very difficult to see exactly where you're going wrong, but you can use this as a starting point to narrow down your issue.
链接地址: http://www.djcxy.com/p/72934.html