Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-09-13 17:56:31


Brian McNamara <lorgon_at_[hidden]> writes:

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

OK, but maybe you should take this to comp.std.c++...

> I think I have two things to say.
>
> FIRST,
>
> 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?

Well, yeah, except we're probably changing the standard to require
that specific algorithms call swap without qualification. See
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#226 and
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1439.htm

> 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 );
> }

You clearly didn't read the whole of N1296.
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2001/n1296.asc
considers that approach, and adds:

    "This kind of helper classes are commonly used to emulate partial
    specialization of function templates.

    A disadvantage of this solution is the number of new class
    templates that have to be introduced into the standard
    library. The ability of users to specialize both the algorithm and
    its corresponding helper class template may also prove problematic
    and lead to subtle bugs.

    As already noted, this solution cannot be applied to standard
    functions that are not templates, like std::abs. This problem may
    be solved by turning the functions that need specializing into
    templates."

> I imagine there must be something wrong either with (1) my understanding
> of the problem, or (2) my solution

There's something wrong with every solution, as the paper makes clear
;->

> 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.

Just read the whole paper; I think it provides a fairly complete
survey of the issues.

> 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
> http://lists.boost.org/MailArchives/boost/msg40245.php
> suggest to me that SFINAE may not capable of doing everything we might
> like it to do.

That is true, but has_member isn't one of those things it's incapable
of.

> And even if the standard says it should, I think this is still a
> long time away from being usable in today's compilers

Not so. My list of unsupported compilers is given by:

#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) \
 || BOOST_WORKAROUND(__GNUC__, <= 2 && __GNUC_MINOR__ <= 95) \
 || BOOST_WORKAROUND(__MWERKS__, <= 0x3000) \
 || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
# define BOOST_NO_SFINAE // "Substitution Failure Is Not An Error not implemented"
#endif

and in fact for some limited cases MSVC6/7 also can do SFINAE. But I
haven't tested everything. I have no idea what really tough
implementations like Sun and HP do, but then again almost nothing
from Boost works with those 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").

You need different kinds of SFINAE to detect member class templates,
and overloading can indeed cause problems (though not if you're
testing for a specific member function signature as John is doing).
That said, we're only talking about changing the *default*
implementation of swap. There's nothing to stop users from providing
their own swap implementation if for some pathological reason they
really want to design their classes with overloaded swap member
functions.

> 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.)

I think a little of both. It's true that, depending on what kind of
member you're testing for, has_member_foo can run into trouble. In
this case, it's not serious because there's always another way to do
it.

> 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. :)

I think the appropriate people are all reading this list and the
standard library reflector, where the issue has also been raised. I
think it's good that you're airing your concerns here; all the same
please try to be sure of what you're saying. Otherwise, it could
easily turn into FUD.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk