Boost logo

Boost :

From: Gennaro Prota (gennaro_prota_at_[hidden])
Date: 2003-02-02 11:23:22


On Sun, 02 Feb 2003 08:35:56 -0500, David Abrahams
<dave_at_[hidden]> wrote:

>> This of course works, but the typedef name is quite "log specific";
>> certainly that's worse than having a generic name available at class
>> scope:
>>
>>
>> template <...>
>> struct static_log2 {
>> typedef ... argument_type; // (*)
>> };
>>
>>
>> As Terje Slettebø noticed in private mail, this is a general problem
>> for any 'compile-time function'.
>
>("metafunction")

Well, the term 'compile-time function' was mine, so if it is an error
it is my fault, not Terje's. Maybe I'm not aligned to the standard
terminology, but to me the prefix meta- means "that refers to
something of its same nature", thus for instance a meta-sentence is a
sentence that talks about sentences, a metarule is a rule about rules
and a metaprogram is a program that generates a program. Since a class
template doesn't generate a function I don't call it a metafunction,
though of course if you intend 'function' in a wider meaning then you
can do that as well.

>> A similar issue, for the run-time counter-part, is solved by
>> std::unary_function and std::binary_function. What should we do for
>> the compile-time case?
>
>I don't think the analogy is a good one. unary_ and binary_function
>just supply the typedefs for /specific/ function argument types.
>
>The compile-time case should be handled by passing types instead of
>numbers. If you need the other interface for convenience or legacy
>reasons you can always write static_log2_c<unsigned long>.
>
>Note that using types can allow you to compute a static log2 of
>extended long values even if the C++ compiler doesn't have them built
>in. One just needs an appropriate wrapper type such as:
>
> template <unsigned long hi, unsigned long lo>
> struct long_long
> {
> typedef long_long type;
> unsigned long hi_value;
> unsigned long lo_value;
> };
>
>and specializations of all of the arithmetic primitive metafunctions
>you'll need to use to operate on it.

Yes, but it's quite overkilling in this case. At a point, you have to
balance the generality with the complexity cost (not to talk, in this
case, about compile times).

>> Note that to use argument_type in the above (*) you have to specify
>> an argument for static_log2, despite the fact that actually the
>> typedef doesn't depend on the value of which you compute the
>> logarithm. Even if you introduce, say, an argument_type<> template,
>> like this:
>>
>> // specialize this as needed
>> template <typename T> struct argument_type;
>>
>> template <static_log2_argument_type x>
>> struct argument_type< log<x> > {
>> typedef static_log2_argument_type type;
>> };
>>
>> you still don't solve the problem of the dummy argument: e.g.
>>
>> argument_type< log<1> > :: type; // why 1?
>>
>> Unfortunately you can't default x to zero in the argument_type
>> specialization above. In fact, in this specific case, you could resort
>> to:
>>
>> template <static_log2_argument_type x = 0>
>> struct log {
>> static const int value = ...;
>> };
>>
>
>You've completely lost me here. I tried to understand it three times,
>and gave up.

Sorry, I should have been clearer. The idea was to use a non-intrusive
way to gather the argument type of a generic unary 'metafunction'. The
template argument_type<>, to be specialized as needed, provided a
uniform interface for that; for instance:

   template <typename T>
   struct argument_type;

   template <>
   struct argument_type<MyMetaFunction> {
     typedef ... type;
   };

For static_log2 you would specialize it as:

   template < unsigned long x >
   struct argument_type< static_log2<x> > {
     typedef unsigned long type;

   };

That, however, still requires you to specify a number (whatever it is)
when requiring the argument type:

  argument_type < static_log2<16> > :: type

whereas I think the intuitive syntax would be:

  argument_type < static_log2<> > :: type

To get the intuitive syntax, you can't use a default value in the
specialization of argument_type, simply because that's illegal. But
you could, if you really strive for it at all costs, use a default
(=0) for static_log2 itself. How ugly (and ad-hoc) that would be is
evident to everyone, so I was just, to say, thinking out loud in the
hope that it could suggest other ideas.

Genny.


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