Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2000-11-02 09:13:47


From: "David Abrahams" <abrahams_at_[hidden]>

> Well, I think "not compiling" is outside the scope of the standard, at
least
> where the library is concerned. The standard never promises that invalid
> uses of the library will fail to compile.

Correct; but having as many invalid uses of the library as possible fail to
compile is a good thing, in general.

> I realize that. And I am not (neccessarily) against FTPS, though providing
> for it does seem like the more difficult way to solve the immediate needs
of
> users. It is clear that we need to explore the two approaches some more
> before we will come up with an acceptable solution.

I'll try to present a more systematic view on the matter. But first, an
example that is too good to skip:

#include <set>

struct base {};

namespace std { void swap(base &, base &); }

struct derived {};

void f()
{
    derived d1, d2;
    std::swap(d1, d2);
}

--
Suppose that I am a library implementor that wants to provide a specialized
swap() for the (non-template) class X. The options are:
namespace std { void swap(X &, X &); }     // #1
template<> void std::swap(X &, X &);        // #2
template<> void std::swap<X>(X &, X &);   // #3
My analysis of the drawbacks of each method:
#1:
* allows invalid uses of std::swap to compile;
* does not require the original std::swap declaration to be visible, which
may lead to unexpected results.
#2:
* uses an error-prone specialization syntax, although in this particular
case things can never go wrong. Nevertheless, programmers learn by example,
so this style should not be encouraged.
#3:
* Syntax is hard to teach.
Your choice? I, personally, would go with #3 any day.
Now, consider the class template Y<T> case:
namespace std
{
    template<class T> void swap(Y<T> &, Y<T> &);                // #4
}
template<class T> void std::swap<Y<T> >(Y<T> &, Y<T> &);  // #5
#4:
* does not suffer from the #1 problems, but may interact badly with #3.
#5:
* requires core changes;
* syntax is hard to teach, although not that hard for someone that already
has mastered #3.
Here it's either #4 or #5, the drawbacks balance each other.
My personal preference is #5 because the feature is not without merits.
An additional comment about the "hard to teach" argument. Which syntax is
(a) easier to teach, (b) less dangerous and error-prone?
template<> void f(int);
or
template<> void f<int>(int);
--
Explanation of the example at the top: in implementation A including <set>
makes std::swap visible, and std::swap(d1, d2) calls the original template.
Implementation B does not make std::swap visible in this case, and
std::swap(d1, d2) uses the overload.
--
Peter Dimov
Multi Media Ltd.

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