Re: [boost] compile-time functions interface

2003-02-02 Thread David Abrahams
Gennaro Prota <[EMAIL PROTECTED]> writes:

> This is a simple question; suppose you have a template like this:
>
>   template < unsigned long x >
>   struct static_log2
>   {
> BOOST_STATIC_CONSTANT( int, value = ...);
>   };
>
>
> and that the implementation you use is absolutely general as far as
> the argument type is concerned; in other words: if C++0x will make
> unsigned long long available you want to replace unsigned long with
> that wider type. Specifically, this is the case for the excellent
> static_log2 implementation suggested by Vesa Karvonen a while ago on
> this list. A first, obvious, way to do this is to typedef the argument
> type:
>
>
>namespace boost {
>   typedef unsigned long static_log2_argument_type;
>
>   template < static_log2_argument_type x>
>   struct static_log2 {
> ...
>   }
>
>}

*This* is precisely why you metafunctions should operate on types, not
numbers.  Types are the only fully polymorphic metadata because they
can wrap anything else (well, as soon as we get template typedefs they
will be able to wrap anything else, but they're close enough now).
That's why MPL has integral_c.

> 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")

> 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.

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 
 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.

> 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  struct argument_type;
>
>template 
>struct argument_type< log > {
>  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  
>struct log { 
>  static const int value = ...; 
>};
>

You've completely lost me here.  I tried to understand it three times,
and gave up.


-- 
   David Abrahams
   [EMAIL PROTECTED] * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution

___
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost



[boost] compile-time functions interface

2003-02-02 Thread Gennaro Prota
This is a simple question; suppose you have a template like this:

  template < unsigned long x >
  struct static_log2
  {
BOOST_STATIC_CONSTANT( int, value = ...);
  };


and that the implementation you use is absolutely general as far as
the argument type is concerned; in other words: if C++0x will make
unsigned long long available you want to replace unsigned long with
that wider type. Specifically, this is the case for the excellent
static_log2 implementation suggested by Vesa Karvonen a while ago on
this list. A first, obvious, way to do this is to typedef the argument
type:


   namespace boost {
  typedef unsigned long static_log2_argument_type;

  template < static_log2_argument_type x>
  struct static_log2 {
...
  }

   }

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'. 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?
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  struct argument_type;

   template 
   struct argument_type< log > {
 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  
   struct log { 
 static const int value = ...; 
   };


Since log2<0> gives an error anyway, this would change nothing for the
normal usage of computing a logarithm (i.e.: he should specify the
argument anyway, as it is now). But, with that default, you could
have:


  template <> 
  struct argument_type< static_log2<> > { 
 typedef static_log2_argument_type type;
  };

  // usage:
  argument_type < static_log2<> > :: type


However I don't like too much the idea to have a default argument
(zero) which is a non-sense for the main usage of the template
(calculating an algorithm) and whose only purpose is to use a simpler
template-id in conjunction with argument_type<>. Also this is quite an
ad-hoc approach, not suitable for other "unary compile-time-function
templates" for which no "unusable default" exists. In short: I don't
know what to do :-) Maybe we should simply have the convention that
such templates provide typedefs with standard names, like
argument_type and result_type?

Thoughts?


Genny.

___
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost