Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2002-09-21 00:33:42

>From: "Dirk Gerrits" <dirk_at_[hidden]>

>Terje Slettebø wrote:
>>>From: "Aleksey Gurtovoy" <agurtovoy_at_[hidden]>
>>>Terje Slettebø wrote:
>>>In the posting with my "factorial" metafunction
>>>(, I
>>>propose to make the metafunctions evaluate their own arguments
>>>(apply "::type" to them), just like it happens in run-time functions.
>>>With that, the factorial example becomes (quoting from my posting):
>>>>"value" is another new metafunction. It's a way to provide a generic
>>>>constant, of the type given in the first argument, and the
>>>>value given in the second. Thus, if "Value" is int_c<...>, then
>>>>"value<Value,1>::type" is int_c<1>.
>> I understand you haven't had a chance to read the post-review postings,
>> you say below here, because in the one where I introduced "value," I
>> explained that it was a way to provide a generic constant, so that a
>> metafunction could use any value type (integral_c, int_c, rational_c,
>> fixed_c, etc.), rather than having to write one for each, and it still
>> wouldn't work for any new type.
>> It works like this: If Type is e.g. integral_c<...>, then
>> "value<Type,0>::type" gives integral_c<0>. If Type is rational_c, then it
>> gives rational_c<0,1>, etc.
>Please forgive the insolence of a MPL newbie, but I thought integral_c
>did exactly what your value is supposed to do? And I think that is what
>Aleksey was trying to explain as well.

Well, it would, if integral_c was the only kind of value type you could use
for metafunctions. However, if you for example look in the "mpl/math"
directory, you'll find a couple of others, rational_c and fixed_c. These
represent rational numbers and fixed point numbers, respectively. This means
you can do floating-point calculations in metaprogramming (!) :)

For example, you may have rational_c<int,1,2> (0.5), or
fixed_c<int,3,14159265>. :)

This makes it possible to make functions for floating-point calculations, as
well, such as sin, cos, etc.

It says in the MPL docs that the metafunctions, such as mpl::plus, etc. is
meant to be specialised for the different types, like these. However, for
functions using only these other metafunctions (like factorial does), they
can actually be implemented in a type-independent way. This means you can
make _one_ function, and it works for any of these types, as mentioned. It
saves a lot of duplication. Besides, if a new type is made, the function
will work with it right away.

To do that, such as in the factorial example, you need to be able to say
something like "I want the same type as this, except with another value." In
generic run-time programming, if we have a type, we can do this easily, by
doing Type(value), and it will create a value of the given type. However, in
metaprogramming, unless you use value parameters (and then you only get
integrals), the value is encoded in the type, like integral_c<0>. So you
need to be able to perform the transformation from integral_c<...> to
integral_c<N>, N being an arbitrary value. To illustrate the use, I need to
quote factorial, again:

template<class V>
struct factorial
  typedef typename V::type Value;

  typedef typename apply_if<equal_to<Value,value<Value,0> >,
    mul<Value,factorial<prior<Value> > >
>::type type;

Here, we don't know what type Value is. It could be integral_c, int_c,
rational_c, fixed_c, etc. Therefore, we _can not_ just use integral_c in the
routine; that fixes it to work just for integral_c, and nothing else. In
short, it won't be generic. Instead, the "value<Type,new value>::type" will
make a new value, of the same type as "Type," with the given value. This
ensures that the constants used in the routine will be of the same type as
the value type used for it, no matter what type that is.

I hope that was more understandable.



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