Boost logo

Boost Users :

From: Ian McCulloch (ianmcc_at_[hidden])
Date: 2005-03-04 12:01:36


Peter Dimov wrote:

> David Abrahams wrote:
>> "Peter Dimov" <pdimov_at_[hidden]> writes:
>>
>>> David Abrahams wrote:
>>>
>>>> ADL might not be the best customization solution.
>>>
>>> You keep saying that, but I keep disagreeing. ADL is the best
>>> customization solution. Not flawless, just better than any of the
>>> alternatives.
>>
>> I guess I haven't seen enough be definitively convinced one way or the
>> other. I have heard stories from people who switch to dispatching via
>> specialization and report how much better things get. Furthermore,
>> Daveed Vandevoorde has convinced me that it is far easier to reason
>> about. The rules for matching partial specializations are trivial
>> compared to the mess you have to consider when there is overloading.
>> The inconvenience of specialization is ugly, but it seems like a
>> one-time cost that may be justified for what it buys us.
>
> That's the thing. It doesn't actually buy us anything. It only claims to
> avoid potential problems.

I would disagree with that - it buys quite a lot, although for simple uses
the extra syntax might not be worth it.

>
> * Uglier syntax for defining a specialization.

IME, this is the biggest cost. I would include also the (one-off) cost of
providing a forwarding function to get a sane syntax for the outside world.
That is OK if you have a closed set of functions because the forwarding
function can be defined by the library, but if the library is merely
providing a framework for user-supplied algorithms it becomes a bit messy.

>
> * Coupling; you need to include a primary template.

Ok, but what does that primary template do? Surely nothing, or some very
conservative default.

>
> * Does not allow a base-specific version to be picked up automatically for
> derived classes.

But you can use a partial specialization heirachy instead. Something like

template <typename T>
struct forward_iterator {};

template <typename T>
struct bidirectional_iterator {};

// ...

typedef forward_iterator<void> forward_iterator_t;
typedef forward_iterator<bidirectional_iterator<void> >
bidirectional_iterator_t;

// ...

template <typename T, typename Tc = typename iterator_concept<T>::type>
struct my_algo_impl {};

template <typename T, typename Ti>
struct my_algo_impl<T, forward_iterator<Ti> >
{
   // implement my_algo for forward iterators
};

template <typename T, typename Ti>
struct my_algo_impl<T, forward_iterator<bidirectional_iterator<Ti> > >
{
   // implement my_algo for bidirectional iterators
};

Unfortunately, I don't know of a way of reducing the amount of typing needed
for overloads on a deep heirachy, other than macros.

>
> * Does not allow non-exact matches.

You could use enable_if<is_convertible<T,U> >. Of course that is asking for
trouble with ambiguous template specializations, but you would have a
similar problem using ADL, with ambiguous overloads. And its certainly
easier to control a set of template specializations verus an ADL overload
set.

>
> * If four libraries need the same operation, you need to specialize four
> primary templates.

Compare to four libraries using an ADL lookup on the same function name, but
requiring different semantics?

>
> In practice people tend to respect de-facto standards; a + b is an
> addition, and swap(a, b) swaps a and b. The main fight is over who gets to
> keep the primary template. But this is not really a problem with ADL
> customization points, because in their purest form, there is no primary
> template. The primary template is usually a compatibility workaround for
> types that do not support the ADL interface yet.

Sure, for de-facto standard operations, ADL works fine.

Cheers,
Ian


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net