|
Boost : |
From: Gennaro Prota (gennaro_prota_at_[hidden])
Date: 2003-02-02 07:47:44
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.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk