Boost logo

Boost :

From: Aleksey Gurtovoy (alexy_at_[hidden])
Date: 2001-11-26 12:55:03

Emily Winch wrote:
> Yes, it was the practical value that I was missing :) But,
> practical value or not, it makes sense that all functions
> over types have a consistent interface.

Yes, and we already have a de-facto standard:

template<typename T1, .., typename Tn>
struct value_func
    static N const value = /* ...*/; // N is some integral or enumerated

template<typename T1, .., typename Tn>
struct type_func
    typedef /* ...*/ type;

The above "interface rules" are applicable not only to compile-time
"functions", but to compile-time "objects" too:

template<long N>
struct int_t
    BOOST_STATIC_CONSTANT(long, value = N);

Difference between "functions" and "objects" here is kind of subtle, though
:). Unfortunately, things do not always fit that "value/type" pattern.
Consider, for example, mpl::fixed_t<> template that represents compile-time
fixed-point arithmetic type:

template<long IntegerPart, unsigned long FractionPart>
struct fixed_t
    BOOST_STATIC_CONSTANT(long, integer_part = IntegerPart);
    BOOST_STATIC_CONSTANT(unsigned long, fraction_part = FractionPart);

The template just can provide you a meaningful "value" interface. And there
are cases where compliance to the above interface rules is possible, but not
necessary desirable; 'type' can be too "impersonal" for a function return
value; after all, almost everything you operate at compile time is a type
:). Often it's not a problem, for example, rewriting



doesn't add much value; some may argue that the latter version is indeed
_harder_ to read than the first one. But there are cases when choosing a
more specific name for a function's result typedef _does_ improve
readability and expressiveness of the code - consider, for example,
mpl::find<> algorithm:

   mpl::find<type_list, T>::type

What do you think it returns? :). Well, even if you guessed right, I think
it's much easier to answer the same question when the above line is written

   mpl::find<type_list, T>::iterator

(BTW, renaming the function to "find_T_and_return_iterator" is not something
that I am very keen of :). Still, even for algorithms, having a "type"
interface somewhere in a "backyard" is IMO an obligatory option, because it
makes combination of those compile-time functions and passing them around
much easier. For example, one can easily implement 'transform' algorithm in
terms of 'mpl::for_each' and 'mpl::push_back' exactly because 'push_back'
supports "type" interface, so you can pass it to 'compose_*' (which produces
a function class with "type" interface too :):

          typename InputSequence
        , typename OutputSequence
        , typename UnaryOperation
    struct transform
        typedef typename mpl::for_each<
            , OutputSequence
            , mpl::compose_f_x_hy<
                  , UnaryOperation
>::state sequence;

> Last night I finally managed to spend some time looking at
> mpl and at the tuple extension stuff. Well, it hurts my head :)
> Some documentation would be really useful!

I'll check in something in a few days.

> There is certainly a lot in common between the functionality
> of my tuple stuff and your typelist stuff. There seems to be less
> commonality in the approaches we are using to get there,
> which is a shame.

One particular commonality that I was talking about is (IMO) in tuple
algorithms and iterators. For example, as far as I can see, your 'for_each'
and my 'for_each' do pretty much the same thing, except that mine allows
function object to change its type on each step of iteration (and ignoring
the fact that my compile-time check for iterators' equality is kind of
strange :).

> So, my current plan is to spend some more time looking at
> your stuff, but mainly to get mine up to scratch and make it
> available so that there is something concrete to discuss. At
> that point, any comments would be extremely welcome, and
> things can move from there.

Sounds good!


Boost list run by bdawes at, gregod at, cpdaniel at, john at