Boost logo

Boost :

Subject: Re: [boost] [guidelines] why template errors suck
From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2010-09-28 18:42:27


On Tue, Sep 28, 2010 at 3:36 PM, Daniel Walker
<daniel.j.walker_at_[hidden]> wrote:
> On Tue, Sep 28, 2010 at 1:48 PM, joel falcou <joel.falcou_at_[hidden]> wrote:
>> On 28/09/10 19:37, David Abrahams wrote:
>>>
>>> This BehaveAsPair thing doesn't identify any real abstraction.  I
>>> promise you're not going to come across any uses for BehaveAsPair
>>> other than in solving the exact implementation problem you're
>>> attacking.
>>>
>>
>> I see
>>>
>>> In short, it lacks "truthiness." :-)
>>>
>>
>> Agreed
>>>
>>> Was there something unsatisfying about the solution I posted in
>>> http://permalink.gmane.org/gmane.comp.lib.boost.devel/209012 ?
>>>
>>
>> Nope, I just missed it.
>
> Oh wait! I think I have another example that's more truthy. :) I'll
> use Boost.ConceptCheck to flesh it out. Let's define the concept of an
> AdditivePair to represent the arguments to binary addition. To model
> the concept a type needs to support first(x), second(x) and add(x) for
> an object x where all three functions have integer values. So, the
> (simplest) concept checking class would be:
>
> template <class T>
> struct AdditivePair {
>    BOOST_CONCEPT_USAGE(AdditivePair)
>    {
>        int a = first(x);
>        int b = second(x);
>        int c = add(x);
>    }
>    T x;
> };
>
> We can now write Eric's function using concept requirements.
>
> template<class T>
> BOOST_CONCEPT_REQUIRES(
>    ((AdditivePair<T>)),
>    (int)
> ) sum_ints( T const & t )
> {
>    return add( t );
> }
>
> We can now adapt std::pair<int,int> to model the AdditivePair concept.
>
> int first(std::pair<int,int> x) { return x.first; }
> int second(std::pair<int,int> x) { return x.second; }
> int add(std::pair<int,int> x) { return first(x) + second(x); }
>
> And we can also adapt int to model the AdditivePair concept; i.e. int
> is an additive pair where the second member is 0.
>
> int first(int x) { return x; }
> int second(int x) { return 0; }
> int add(int x) { return x; }
>
> That seems pretty natural to me.

Crap. I just realized that Eric's original function was recursive!
Doh! Let me try that again. To handle recursive pairs the AdditivePair
concept needs a pair_traits class, which will determine the return
types of first(x) and second(x). The concept checking class is almost
the same as before:

template<class> struct pair_traits;

template <class T>
struct AdditivePair {
    BOOST_CONCEPT_USAGE(AdditivePair)
    {
        typename pair_traits<T>::first_type a = first(x);
        typename pair_traits<T>::second_type b = second(x);
        int c = add(x);
    }
    T x;
};

Eric's function can still use concept requirements. In fact, no
changes are required for the recursive version.

template<class T>
BOOST_CONCEPT_REQUIRES(
    ((AdditivePair<T>)),
    (int)
) sum_ints( T const & t )
{
    return add( t );
}

Adapting pair<int,int> and int to model AdaptivePair is basically the
same, but now we need to specialize the traits class.

// adapt pair
int first(std::pair<int,int> x) { return x.first; }
int second(std::pair<int,int> x) { return x.second; }
int add(std::pair<int,int> x) { return first(x) + second(x); }
template<> struct pair_traits<std::pair<int,int> > {
    typedef int first_type;
    typedef int second_type;
};

// adapt int
int first(int x) { return x; }
int second(int x) { return 0; }
int add(int x) { return x; }
template<> struct pair_traits<int> {
    typedef int first_type;
    typedef int second_type;
};

And now we can adapt recursive pairs to model the AdditivePair concept.

template<class T0, class T1>
T0 first(std::pair<T0,T1> x) { return x.first; }

template<class T0, class T1>
T1 second(std::pair<T0,T1> x) { return x.second; }

template<class T0, class T1>
int add(std::pair<T0,T1> x) { return add(first(x)) + add(second(x)); }

template<class T0, class T1>
struct pair_traits<std::pair<T0,T1> > {
    typedef T0 first_type;
    typedef T1 second_type;
};

Now that works as expected. Sorry for any confusion. (It illustrates
an interesting point, though. I was concerned with the base case in
Eric's recursion where I a saw unary function called sum_ints, which
didn't make sense to me conceptually since addition is a binary
operation. So, I was focused on trying to work out the concept modeled
by the argument to sum_ints, and missed the fact that sum_ints was
recursive. Later, though, having the concept worked out made
implementing the recursive version trivial.)

Daniel Walker


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