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 <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 = ...; 
   };


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

Reply via email to