Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2003-02-02 13:33:12


>From: "David Abrahams" <dave_at_[hidden]>

I'm combining a couple of postings here.

>Gennaro Prota <gennaro_prota_at_[hidden]> 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<T, value>.

> *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<T, value>.

Yes, of course. I thought it could be hard to find a way to provide the
types for such a metafunction like static_log2, when it turns out that a
solution to it is to not do it like that in the first place, as you say.
I've even used this polymorphic ability of MPL to write examples of generic
metafunctions like factorial<>. I just didn't think of of that, as this
metafunction worked in a different way. The answer is to change the way of
doing it, rather than finding a way to do it with the current version of the
metafunction.

> > As Terje Slettebø noticed in private mail, this is a general problem
> > for any 'compile-time function'.

Just to clarify here, what I meant was that this wasn't something specific
for this particular metafunction, of course, so it could be good to find a
general solution, such as the above one.

>From the next posting:

> > Gennaro Prota <gennaro_prota_at_[hidden]> writes:

> From: "David Abrahams" <dave_at_[hidden]>

> > 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
>
> I don't even think it works. Throwing this at Comeau online:
>
> template <unsigned long N>
> struct static_log2 {};
>
> template <class T>
> struct argument_type;
>
> template < unsigned int x > // ***
> struct argument_type< static_log2<x> > {
> typedef unsigned long type;
> };
>
> Yeilds:
>
> "ComeauTest.c", line 6: error: constant "x" is not used in template
argument list
> of class template "argument_type<static_log2<x>>"
> template < unsigned int x >
> ^
>
> But this works again if I change *** to unsigned long. None of my
> other compilers agree, but I am inclined to believe EDG. Why should
> it be any different from substituting "class x" at ***?

I'm not sure what you mean, here. The error above comes from argument type
mismatch, as the type of "x" is unsigned int, while static_log2<> expects an
unsigned long, so there needs to be a conversion. Therefore, the partial
specialisation doesn't work. As you note, if you change it to match, with
unsigned long, it works. I think EDG is right on this one, that there has to
be an exact match, except top-level cv-qualification.

> > 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.
>
> IMO, unless EDG is wrong you're going to have to use types if you want
> to generalize it.

You can use the syntax Genny used: "argument_type < static_log2<16> > ::
type". However, unless you use an arbitrary default argument for
static_log2, just for this purpose, you need to specify an arbitrary
constant, instead, as shown here, just to get the type.

Regards,

Terje


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk