views:

273

answers:

6

The C++ standard prohibits declaring types or defining anything in namespace std, but it does allow you to specialize standard STL templates for user-defined types.

Usually, when I want to specialize std::swap for my own custom templated type, I just do:

namespace std
{
  template <class T>
  void swap(MyType<T>& t1, MyType<T>& t2)
  {
     t1.swap(t2);
  }
}

...and that works out fine. But I'm not entirely sure if my usual practice is standard compliant. Am I doing this correctly?

+2  A: 

Why won't you just define swap in MyType's namespace and exploit argument-dependent lookup power?

Alexander Poluektov
This would be a perfect comment. *\*hint\* \*hint\**
Roger Pate
I don't see why, he offers a correct solution to the OP's problem.
Manuel
It does not work for the case of templates. If you want to call `swap` function for the type `T` you do not know how. `swap(a,b)` does not work if `a` and `b` are `int`. `std::swap(a,b)` does not work if `a` and `b` are `Bar` or OP's `MyType<T>`.
Alexey Malistov
That's why it's good idea to have `using namespace std` in beginning of your functions. Unless Standard permits overloading in `std` ADL + using namespace std should do the job.
Alexander Poluektov
@Alexey: This is why you *must* always use `swap` as follows: `using std::swap; swap(a, b);` instead of `std::swap(a, b);`
Konrad Rudolph
+4  A: 

What you have is not a specialization, it is overloading and exactly what the standard prohibits. (However, it will almost always currently work in practice, and may be acceptable to you.)

Here is how you provide your own swap for your class template:

template<class T>
struct Ex {
  friend void swap(Ex& a, Ex& b) {
    using std::swap;
    swap(a.n, b.n);
  }
  T n;
}

And here is how you call swap, which you'll notice is used in Ex's swap too:

void f() {
  using std::swap; // std::swap is the default or fallback
  Ex<int> a, b;
  swap(a, b); // invokes ADL
}

Related: Function template specialization importance and necessity

Roger Pate
A: 

Because of argument dependent (aka Koenig) lookup, I believe you can specify your own swap in the namespace of the type you want it for and it will be found in preference to ::std::swap. Also, I believe the template for ::std::swap will expand differently for classes that have their own swap member function and so you can add that member function to the class and that will be used for your type.

Omnifarious
Who downvoted my answer and why? I believe it's correct.
Omnifarious
Yeah, same thing happened to me. I've upvoted you to restore justice :)
Manuel
Though it wasn't my downvote, you're wrong about std::swap detecting a swap member and using it. (I know of no way it could be written to do that in current C++, but regardless it's required that it not.)
Roger Pate
@Roger Pate: Interesting, and that's a little disappointing. I think it can be implemented that way with a clever use of SFINAE rules.
Omnifarious
@Omni: If you come up with a way, I'd love to see it, as I could use it in other places.
Roger Pate
A: 

Define your type and your swap function in the same namespace:

namespace foo
{
   struct Bar
   {
   };

   void swap(Bar & t1, Bar& t2)
   {
     // whatever
   }
}

int main()
{
    using std::swap;
    foo::Bar a, b;
    swap(a, b); // Argument-dependent lookup chooses foo::swap
                // if it exists, or else reverts to std::swap
}
Manuel
His *MyType* is a class template instead of a class, which makes for a slightly more complicated example, especially when you consider that swap must usually be a friend (or call a swap method, but why have two ways to do the same thing?).
Roger Pate
I don't think the fact that mine is not a template makes such a difference, I just wanted to get rid of some boilerplate. But I'll concede that your answer is better because I've forgotten the "using std::swap" part. And of course if I add it now you'll say that I copied you :)
Manuel
@Manuel: Feel free to add it, copying good ideas is encouraged. Once you understand that boilerplate and the ramifications it becomes simple (do you know how to make a friend declaration that only friends a specific instantiation of a function template rather than any instantiation?), but it's something that frequently trips up those new to it and is definitely worth giving an example of when that's what is asked about, if you're giving examples. (I'm trying to help you give better answers, BTW, no offense meant. :P)
Roger Pate
@Roger - OK, none taken. Thanks for the tip.
Manuel
It does not work for the case of templates. If you want to call `swap` function for the type `T` you do not know how. `swap(a,b)` does not work if `a` and `b` are `int`. `std::swap(a,b)` does not work if `a` and `b` are `Bar` or OP's `MyType<T>`.
Alexey Malistov
@Alexey: This answer works and also see my answer; a using declaration + unqualified call makes it work. And please try not to post the same comment twice on two answers in the same question, just pick one.
Roger Pate
@Alexey - My code works fine when `Bar` is a class template. See it yourself: http://codepad.org/KqF5k9oy
Manuel
Who's downvoting this? See the codepad link in my previous comment: this code works!
Manuel
@Manuel: Don't worry about the downvotes if it's lost rep that bothers you, I've added this answer to my (sadly very long) bookmark queue for upvotes, and remember to save your codepad.org pastes so they don't disappear. (The link is in the upper right, and you'll need to login.)
Roger Pate
@Manuel: Right. Your code does work because `using std::swap`. I do not like this idea. But you are right.
Alexey Malistov
@Roger - I don't care about the rep, it's just that when I see an answer with negative score I tend to assume there's something wrong with it.
Manuel
A: 

Define own swap. This function must call std::swap for any type T except your types.

namespace help // my namespace
{ 

  template <class T> 
  void swap(T& t1, T& t2) 
  { 
     ::std::swap(t1, t2);  // Redirect to std for almost all cases
  } 

  // My special case: overloading
  template <class T> 
  void swap(MyType<T>& t1, MyType<T>& t2) 
  { 
     t1.swap(t2); 
  } 

}  //  namespace help 

// Sample
int main() 
{

   MyType<int> t1, t2; // may be add initialization
   int i1=5, i2=7;

   help::swap(t1, t2); //  Your swap
   help::swap(i1, i2); //  Redirect to std::swap
}
Alexey Malistov
If you're going to do that, just use boost::swap and don't reinvent the wheel. But this throws generality completely out the window. You completely miss how to write a generic function which uses help::swap for your types, something_else::swap for other types, etc., and std::swap for everything else.
Roger Pate
A: 

Edit

See Scott Meyer's article: See Effective C++ 3rd Edition, item 25: Consider support for a non-throwing swap (p106-p112) for a confirmation of my answer.

Original answer

Scott Meyers wrote about this, so my answer comes from memory.

First, define a swap function in the namespace of your class. For example :

namespace MyNamespace
{
   class MyClass { /* etc. */ } ;

   template<typename T>
   class MyTemplate { /* etc. */ } ;

   void swap(MyClass & lhs, MyClass & rhs)
   {
      // the swapping code (**)
   }

   template<typename T>
   void swap(MyTemplate<T> & lhs, MyTemplate<T> & rhs)
   {
      // the swapping code (**)
   }
}

Then, if possible (it is not always possible for templated classes (*) ), specialize the swap function in the namespace std. For example :

namespace std
{
   template<>
   void swap<MyNamespace::MyClass>(MyNamespace::MyClass & lhs, MyNamespace::MyClass & rhs)
   {
      // the swapping code (**)
   }

   // The similar code for MyTemplate is forbidden, so don't try
   // to uncomment it
   //
   // template<typename T>
   // void swap<MyNamespace::MyTemplate<T> >(MyNamespace::MyTemplate<T> & lhs, MyNamespace::MyTemplate<T> & rhs)
   // {
   //   // the swapping code (**)
   // }
}

The, when using the swap function, do it indirectly, importing the std swap function into your scope. For example :

void doSomething(MyClass & lhs, MyClass & rhs)
{
   // etc.

   // I swap the two objects below:
   {
      using std::swap ;
      swap(lhs, rhs) ;
   }

   // etc.
}

void doSomethingElse(MyTemplate<int> & lhs, MyTemplate<int> & rhs)
{
   // etc.

   // I swap the two objects below:
   {
      using std::swap ;
      swap(lhs, rhs) ;
   }

   // etc.
}

As soon as I have access to my books, I'll post here the exact reference.

  • (*) template partial specialization of a function is forbidden
  • (**) of course, a good pattern is to have a "swap" method declared in the class, have the swap functions call the swap method, and have the user call the swap function.
paercebal
This does not work for class templates, as you cannot partially specialize functions and cannot know in advance all the specializations of class templates you write. (The using declaration isn't important for this specialization, incidentally.)
Roger Pate
Your edit brings the answer closer to the mark, but since the question is about class templates in particular, it appears you're not even answering what was asked. (It is not, in practice, *ever* possible to know all the specializations.)
Roger Pate
@Roger Pate: My answer was generic, so MyClass could be anything, but for clarity's sake, I added the example code for MyTemplate, which is a templated class. Of course, this code compiles and works (tested on g++)
paercebal
The attempted specialization you commented out is illegal, as you can't partially specialize functions.
Roger Pate
@Roger Pate: Of course it is illegal. This is why I wrote "The similar code for MyTemplate is forbidden ..." above it... But I felt it was better to write it, comment it and explained why it was commented ("it is forbidden") than just leave it out for the reader to find why it wasn't there.
paercebal
Ah, I misunderstood, interpreting you as meaning the standard specifically prohibits overloading things in the std namespace, which is a separate restriction and the one much more commonly encountered.
Roger Pate