Boost logo

Boost :

Subject: Re: [boost] [concept] concept-based overloading (N2081)
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2010-05-27 15:13:08


On Thu, May 27, 2010 at 1:38 PM, Lorenzo Caminiti <lorcaminiti_at_[hidden]>wrote:

> How do I use Boost.ConceptCheck and/or Bosot.EnableIf to implement
> concept-based overloading (as discussed in N2081)?
>
> How do I program this in C++ using Boost libraries?
>
> N2081 briefly mentions this can be done in C++ using SFINAE, etc. I
> think I could use `enable_if` if I had some sort of
> `is_input_iterator` metafunction..

You pretty much need to use tag dispatching to be able to handle
concept-based overloading with refinement of concepts, rather than straight
SFINAE. The main reason for this is most easily shown with some pseudo code:

// Imagine that these represent true overloads based on concepts
void foo( forward_iterator it ); // foo 1
void foo( random_access_iterator it ); // foo 2

// SFINAE enable_if-style expressions
template< typename T >
typename enable_if< is_forward_iterator< T > >::type bar( T it ); // bar 1

template< typename T >
typename enable_if< is_random_access_iterator< T > >::type bar( T it ); //
bar 2

Now do "foo( some_std_list.begin() )". As you'd expect, foo 1 is called.
Similarly, do "bar( some_std_list.begin() )". Again, as you'd expect, bar 1
is called

However, what if you call "foo( some_std_vector.begin() );" foo 2 is of
course called, but if you do "bar( some_std_vector.begin() )" your
expression is now ambiguous since T is a random access iterator, which in
turn is also a forward iterator via refinement. Both overloads are valid
candidates with one no better than the other. The "foo" example works
because foo 2 is a better match than foo 1, but with a basic SFINAE
approach, that is not the case.

The way the desired behavior is simulated in C++, as you are probably
familiar with already, is tag dispatch, where the tags are related directly
in C++ through inheritance, allowing the compiler to pick the better match
via overload rules with regard to inheritance for the tag parameter.

There are ways you can probably think of, avoiding tag dispatch, to get the
overloads in the "bar" example to be picked as you'd like for this simple
case, but it would be tough to make the overloads "future proof" with
respect to unknown refinements and overloads that may be written at some
later point in time. With tag dispatch, no such problem exists and writing
overloads is still fairly intuitive. Unfortunately, even in C++0x, I
personally do not believe that there is a better way to do this without tag
dispatch.

-- 
-Matt Calabrese

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