Boost logo

Boost :

From: Brian McNamara (lorgon_at_[hidden])
Date: 2003-09-12 22:26:10

This is somewhat off-topic, I suppose, as it's more about "the C++
standard" than "Boost", so forgive me.

I think I have two things to say.


On Thu, Sep 11, 2003 at 06:13:43PM +0300, Peter Dimov wrote:
> Quoting from N1296:
> [begin quote:
> Only fix std::swap
> ------------------
> Although this paper so far discusses the broad problem of standard
> functions in general, many developers actually need to specialize one
> and only one algorithm, namely std::swap.

... so, I _think_ maybe I understand "what the problem is" with swap(),
but I may be wrong, so correct me if I am. Here's what I see as the
issue that causes the fuss:

 - std::swap() provides a default swap implementation.

 - std::swap() may not be the best implementation for your UDT. You
   could do it better/faster/whatever.

 - The problem is, you cannot overload swap() in namespace std, because
   the standard prohibits overloads in std.

 - The problem is, you cannot partially specialize swap(), since swap()
   is a template function, and template functions cannot be partially
   specialized in C++ (only template classes can).

 - The problem is, while you could write swap(MyUDT&,MyUDT&) in your own
   namespace and rely on Koenig lookup, there is still the issue that
   std:: algorithms are making explicit calls to std::swap(), which
   means Koenig lookup never kicks in.

Is all this true?

If it is, it seems to me that the "easiest" solution is this:

Change the definition of the standard library. Have it define std::swap
like this:

   template <class T>
   struct swap_helper {
      static inline void go( T& x, T& y )
      { /* old std::swap impl here */ }
   template <class T>
   inline void swap( T& x, T& y ) {
      swap_helper<T>::go( x, y );

As far as I can tell, this change is invisible to all the existing C++
code in the world. However, now users can specialize swap:

   template <class T> struct MyContainer { /* ... */ };
   namespace std {
      // We _are_ allowed to _partially_specialize_ std::entities
      template <class T>
      struct swap_helper<MyContainer<T> > {
         static void go( MyContainer<T>& x, MyContainer<T>& y )
         { x.swap(y); /* or whatever you do for MyContainers */ }

Now even a fully-qualified call to std::swap() will call the
specialized version.

I imagine there must be something wrong either with (1) my understanding
of the problem, or (2) my solution, or else I imagine this issue would
have already disappeared a long time ago. But I've never quite
understood all the issues around "swap", so perhaps someone here can set
me straight.

SECOND, I just want to mention that I am not convinced that the
"has_member_foo" implementations (discussed elsewhere in this thread)
actually work. Prior messages like
suggest to me that SFINAE may not capable of doing everything we might
like it to do. And even if the standard says it should, I think this is
still a long time away from being usable in today's compilers (but
perhaps I am just pessimistic). If you have found a compiler on which
your "has_member_foo" implementation appears to work, I would encourage
you to "stress test" it on types like
   struct type1 {
      void foo(); void foo(int); // foo is an overloaded name
   struct type2 {
      template <class T> void foo(); // foo is a template function
   struct type3 {
      template <class T> struct foo {}; // foo is a template struct
and other "tricky" cases. My previous experience suggests that even if
"has_member_foo" appears to work on simple cases, it may fail in
unexpected ways on pathological cases (where "fail" might mean either
"with respect to this particular compiler" or "with respect to the
language standard").

So my point is just that I urge caution before believing "here is an
implementation of has_member_foo that really works!" (I dunno if I am
being pessimistic or realistic.) Anyway, undoubtedly there are people
who will know more about this issue than I do, so find out who they are
and talk to them. :)

-Brian McNamara (lorgon_at_[hidden])

Boost list run by bdawes at, gregod at, cpdaniel at, john at