27 February 2009

Template specialization for std::swap

One of the algorithms in C++'s STL is swap, a templated function which takes two arguments of the same class and switches them. By default, it creates a new object and performs two copies, but for STL containers (such as std::list, which I was using) it has its own template specialization to only copy their internal pointers and not any actual data. This makes, by default, std::swap way more efficient on an STL container than everything else.

I have a class Census inside a namespace iMc, and it has-a std::list to store a bunch of particles. I'd like to call std::swap(iMc::Census& a, iMc::Census& b) but not copy all the particles inside the list. The solution was obvious and allowed: create a new specialization for my own class that calls  std::swap on the std::list :
namespace std {
template<>
inline void swap<iMc::Census>(iMc::Census& a, iMc::Census& b)
{
std::swap(a._particles, b._particles);
}
} // end namespace std

Well, because the _particles list was private, I had to make this function a friend of iMc::Census. Easy, right? Wrong. It turns out everything on the internet; that talks about templated friend functions is a lie! No matter what I did, I received a bunch of weird errors.
namespace iMc {
class Census {
private:
template<typename T> friend void std::swap(T& a, T& b);
...
};
}
gives
build/imclib/Census.hpp:64: error: 'void std::swap(iMc::Census&, iMc::Census&)' should have been declared inside 'std'

and
friend template<> void std::swap<iMc::Census>(iMc::Census& a, iMc::Census& b);
gives
build/imclib/Census.hpp:64: error: expected unqualified-id before 'template'


Well, it turns out that the correct answer is to have
namespace iMc {
class Census {
private:
template<typename T> friend void std::swap(T& a, T& b);
...
};
}
Who would have guessed? I even checked Stroustroup's reference book, and it didn't look like it had syntax for templated friend functions in there. Hopefully no one else has to fool around and waste an hour of their time trying to do this.

0 comments:

Post a Comment