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

上一篇: 如何使用与成员函数相同的名称来调用内联朋友函数?

下一篇: 为C ++模板类提供swap()会打破std :: swap()?