Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-02-02 15:02:23

Gennaro Prota <gennaro_prota_at_[hidden]> writes:

> --- David Abrahams <dave_at_[hidden]> wrote:
>> You can do that, but IIUC it won't get you where Genny's trying to go:
>> namely that if static_log2 happens to get adjusted so its parameter is
>> an unsigned long long constant, you can detect that without causing an
>> error.
> No. Because in the real code I would have written:
> // actually in namespace detail
> typedef unsigned long static_log2_arg_type; // (*)
> template <static_log2_arg_type N>
> struct static_log2 {};
> template <class T>
> struct argument_type;
> template < static_log2_arg_type x > // ***
> struct argument_type< static_log2<x> > {
> typedef static_log2_arg_type type;
> };
> and the only point subject to modification would have been (*). My problem was
> just that I don't like to specify a value when retrieving the argument type.

Yes, I can understand that.

Let me see if I can make my point clearly.

First, why would you ever use argument_type< ... > instead of simply
writing static_log2_arg_type? If you knew you were operating on
static_log2, argument_type doesn't buy you anything. You would only
use argument_type in some kind of generic higher-order metafunction
which, conceptually, is parameterized on another metafunction (that
could turn out to static_log2). OK so far?

Now, consider the limitations on how that higher-order metafunction
can be written. The most naive way to pass a metafunction is to use a
template template parameter:

    template <template <unsigned long> class F>
    struct higher_order_func
        typedef typename argument_type<F<N> >::type arg_type;

Well, that doesn't work for lots of reasons. First, the signature of
higher_order_func already restricts F to be parameterized on unsigned
long. Second, you have to come up with an appropriate value of N.

So what are your alternatives? You can ask the user to deliver a type
argument to higher_order_func instead, like static_log2<0>, but you're
just passing the buck: the user has to know that zero is a magical
value. OK, so the best choice you have left is to ask the user to
pass static_log2<>. But then, most numerical functions don't have a
magical invalid value that they can use as a default. It's no problem
for types (witness MPL's placeholders), but not for numbers. And do
you really want to establish required defaults as part of your
metafunction protocol? That could make it a lot harder to find arity
errors at compile-time.

My point is this: the only thing that would make argument_type
worthwhile, i.e. the ability to do higher-order functional
programming, really requires that metafunctions have a consistent
polymorphic interface (i.e. type arguments and results). So if you
really insist that static_log2 will not take a type argument, that's
fine, but don't waste your time trying to get argument_type to work.

You're not operating in a generic world, because there's no way to
generalize the neccessary default argument to arbitrary metafunctions
with that form. You might as well settle for static_log2_arg_type

                       David Abrahams
   dave_at_[hidden] *
Boost support, enhancements, training, and commercial distribution

Boost list run by bdawes at, gregod at, cpdaniel at, john at