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.