Boost logo

Boost :

Subject: Re: [boost] Provisional Boost.Generic and Boost.Auto_Function (concepts without concepts)
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2010-12-15 20:03:04


On Wed, Dec 15, 2010 at 6:58 PM, Dave Abrahams <dave_at_[hidden]> wrote:

> Eventually, that's where you should end up, IMO. But that shouldn't
> impair your progress now if you have momentum. See links in my
> previous reply for rationale.
>

I must have missed them, I'll take a look.

On Wed, Dec 15, 2010 at 6:58 PM, Dave Abrahams <dave_at_[hidden]> wrote:

> You know, with C++0x you also have variadic macros, which could
> potentially clean up the syntax... or are you already using those?
>

They're used extensively and they do make things much simpler -- without
variadic support, the use of the macros would be so loaded with extra
parentheses and require so many more internal hacks that I probably wouldn't
be working on this at all. As an example, all of the top-level macros are
variadic and all of the arguments that appear to take Boost.Preprocessor
sequences, such as "if" in the RandomAccessIterator concept definition I
posted, actually take "variadic" preprocessor sequences, which are like
Boost.Preprocessor sequences except that they can have elements with
top-level commas or elements that are empty. In fact, the conditions in the
code I posted make use of this if you look carefully -- the is_same and
is_convertible conditions have top-level commas in them since the
metafunctions are binary, which cannot be accomplished with traditional
Boost.Preprocessor sequences. Also, anything that looks like a parameter
list but with the types wrapped in parentheses also are implemented
internally with variadic macros.

> That's still a significant achievement. Great going!
>

Thanks. There are certain simplifications that can be made as some of those
parentheses are there solely for consistency. For instance, something like (
template ( (class) It, (class) DiffT ) ) with Auto_Function could actually
be written as ( template ( class It, class DiffT ) ), however, in some other
places that there are parameter-list-like macro parameters I need to have
the user put those extra parentheses -- the parentheses are what allow me to
separate and examine each parameter when necessary. As an example, imagine:
( function_name, (int a, array< int, 5 > b) )
The problem is, in a "switch" auto function that is used for concept-based
overloads, I need to forward "a" and "b", but when the parameter list is
written as seen above, I have no way of actually pulling out those parameter
names. Even without that comma in the "array" template argument list, it
would be impossible, though commas such as that cause problems in other
places that I use parameters. In the end, rather than requiring users of the
macros to remember when those extra parentheses are required and when they
aren't I opted to just always require them. Unfortunately that makes things
look somewhat hairier.

This actually isn't how I initially had the macro implemented. It used to be
that some places you had to use those extra parentheses and other places you
didn't. This minimized the amount of parentheses you had to use but it was
hard to remember when the parentheses were required and when they weren't.
With effort, I could static_assert if they were required but the user didn't
provide them, but that still doesn't make the rules for when they are
required any more obvious. Even with that approach, always parenthesizing
also worked since I could detect if parentheses were there or not and branch
out accordingly. That code is still sitting around, but I decided to stop
using it since it made the implementation complicated, not to mention that
the rules for when and when not to use these seemingly superfluous
parentheses was complicated as well. If it turns out that the parentheses
really are making things much too hairy, I could go back to making them only
required in particular situations, but for the time being it's easier for me
to leave them as they are,

I'm sure this is much more information about the implementation than you
cared to know, but I'm really trying my hardest to make this actually
usable. There are unfortunately some hard limits to what is possible with
the C++ preprocessor, so the end result will likely not be much simpler than
what you see now. If it turns out to not be worth it, then at the very least
we've learned how not to emulate concept-based overloads in C++ :p It's not
a huge loss since the concepts and concept maps should still be more than
usable on their own. The asserts alone, IMO, have been worth all of the
effort so far.

-- 
-Matt Calabrese

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