Re: [boost] Re: compile-time functions interface

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

> On Sun, 02 Feb 2003 15:02:23 -0500, David Abrahams
> <[EMAIL PROTECTED]> wrote:
>
> [...]
>>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
>>instead.
>
> Yes, your point is very clear and you are undoubtedly right. I've done
> some quick tests with the current implementation of static_log2 and it
> turns out that, even with the most optimistic assumptions, compile
> times increase remarkably as soon as you use a type argument. And
> there are problems with broken compilers as well. Just to clarify it:
> the core of the current implementation is the following template
>


> That's of course important for our faithful broken compilers. If I
> understand you correctly, having a type argument requires PTS
> instead.

No.

> Regardless of that consideration, I tried quickly changing the code to
> this:
>

 That isn't the approach I'd take if I cared about the speed of
a type-based version.  But no time to write the answer up this
minute...

> Note that I haven't included any of the pachydermic boost headers, I
> have just defined integral_c myself. Also, note that this is just a
> hacked up implementation and that I operated on the argument only, the
> result is still *not* a type. In other words I have made just a part
> of the changes that are needed, so the timings I will have with this
> are likely to be lower than the "real ones". Well, the attached test
> yielded:
>
> // original version:
>
> $ ./bash_test.sh
>
> real0m34.672s
> user0m10.610s
> sys 0m22.601s
>
>
> // new version, with type argument
>
> $ ./bash_test.sh
>
> real0m39.096s
> user0m14.970s
> sys 0m22.720s
>
>
> Of course, defining integral_c yourself is not enough because it needs
> compiler workarounds, so in practice you should include the boost
> header. Doing that, timings go to:
>
> $ ./bash_test.sh
>
> real0m42.624s
> user0m15.710s
> sys 0m22.921s

I think you obviously missed my point altogether, which was:

If you just care about speed, use the tiny and simple implementation
you have, and give up on introspecting about the argument type of the
metafunction.

If you just care about generality, build an implementation around
types.  Then you don't have introspect about the argument type,
because the metafunction will work for any argument type that fits the
concept requirements for integral arithmetic.

If you care about both speed and generality, provide both of the above
interfaces.  There are of course various ways you can optimize, for
example specializing the second version so that integral_c where
T fits in an unsigned long just dispatches to the first one.

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



Re: [boost] Re: compile-time functions interface

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

> --- David Abrahams <[EMAIL PROTECTED]> 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 
>   struct static_log2 {};
>
>   template 
>   struct argument_type;
>
>   template < static_log2_arg_type x > // ***
>   struct argument_type< static_log2 > {
>  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  class F>
struct higher_order_func
{
...
typedef typename argument_type >::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
instead.

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



Re: [boost] Re: compile-time functions interface

2003-02-02 Thread Terje Slettebø
>From: "David Abrahams" <[EMAIL PROTECTED]>

> Terje Slettebø <[EMAIL PROTECTED]> writes:
>
> > 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.
>
> cv-qualification??  Whoa, the compiler seems to accept them, but
> they're also ignored.  This compiles:
>
> template  struct foo;
> template  class> class bar {};
> bar x;

Yes, that's what I meant: The types have to match, except for any top-level
cv-qualification difference, as it's ignored, as you say.


Regards,

Terje

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



Re: [boost] Re: compile-time functions interface

2003-02-02 Thread Gennaro Prota

--- David Abrahams <[EMAIL PROTECTED]> 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 
  struct static_log2 {};

  template 
  struct argument_type;

  template < static_log2_arg_type x > // ***
  struct argument_type< static_log2 > {
 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.

Genny.


__
Do you Yahoo!?
Yahoo! Mail Plus - Powerful. Affordable. Sign up now.
http://mailplus.yahoo.com
___
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost



Re: [boost] Re: compile-time functions interface

2003-02-02 Thread David Abrahams
Terje Slettebø <[EMAIL PROTECTED]> writes:

>>From: "David Abrahams" <[EMAIL PROTECTED]>
>> I don't even think it works.  Throwing this at Comeau online:
>>
>> template 
>> struct static_log2 {};
>>
>> template 
>> struct argument_type;
>>
>> template < unsigned int x > // ***
>> struct argument_type< static_log2 > {
>>   typedef unsigned long type;
>> };
>>
>> Yeilds:
>>
>> "ComeauTest.c", line 6: error: constant "x" is not used in template
> argument list
>>   of class template "argument_type>"
>>  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. 

Exactly.  My point is that as far as the template mechanism is
concerned, int, long, and class are all completely disjoint kinds of
metadata -- with one exception: int and long constants are allowed to
inter-convert when you pass one where the other is expected.

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

cv-qualification??  Whoa, the compiler seems to accept them, but
they're also ignored.  This compiles:

template  struct foo;
template  class> class bar {};
bar x;

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

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.

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



Re: [boost] Re: compile-time functions interface

2003-02-02 Thread Terje Slettebø
>From: "David Abrahams" <[EMAIL PROTECTED]>

I'm combining a couple of postings here.

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

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 <[EMAIL PROTECTED]> writes:

> From: "David Abrahams" <[EMAIL PROTECTED]>

> > For static_log2 you would specialize it as:
> >
> >template < unsigned long x >
> >struct argument_type< static_log2 > {
> >  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 
> struct static_log2 {};
>
> template 
> struct argument_type;
>
> template < unsigned int x > // ***
> struct argument_type< static_log2 > {
>   typedef unsigned long type;
> };
>
> Yeilds:
>
> "ComeauTest.c", line 6: error: constant "x" is not used in template
argument list
>   of class template "argument_type>"
>  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

__

Re: [boost] Re: compile-time functions interface

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

> On Sun, 02 Feb 2003 08:35:56 -0500, David Abrahams
> <[EMAIL PROTECTED]> wrote:
>
>>> 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")
>
> Well, the term 'compile-time function' was mine, so if it is an
> error

It's not an error; I was just trying to say that they're equivalent
terms, for clarity.

> it is my fault, not Terje's. Maybe I'm not aligned to the standard
> terminology, but to me the prefix meta- means "that refers to
> something of its same nature", thus for instance a meta-sentence is a
> sentence that talks about sentences, a metarule is a rule about rules
> and a metaprogram is a program that generates a program. Since a class
> template doesn't generate a function 

It can, but not the ones we're discussing.

> I don't call it a metafunction, though of course if you intend
> 'function' in a wider meaning then you can do that as well.

No, I intend "meta-" in the wider meaning of "of or related to
metaprogramming."  It's a lot easier to discuss metafunctions and
metadata than compile-time functions, and types, integral constants,
templates, constant pointers and references, pointers and references
to functions, and pointers to members (whew! did I forget anything?)

As long as we're in the domain of metaprogramming, I think it makes
sense to adopt a few linguistic shorthands (i.e. domain-specific
jargon).

> Yes, but it's quite overkilling in this case. At a point, you have to
> balance the generality with the complexity cost (not to talk, in this
> case, about compile times).

You're the one who brought up generality ;-).  It's easy enough to get
the speed back by using specializations.

> Sorry, I should have been clearer. The idea was to use a non-intrusive
> way to gather the argument type of a generic unary 'metafunction'. The
> template argument_type<>, to be specialized as needed, provided a
> uniform interface for that; for instance:
>
>template 
>struct argument_type;
>
>template <>
>struct argument_type {
>  typedef ... type;
>};


Ah.  Well, there's no way to do what you want in general.  That's just
one among many very good reasons that MPL metafunctions use a truly
polymorphic interface, operating just on types.  If metafunctions
aren't themselves polymorphic, you can't do this kind of detection.

> For static_log2 you would specialize it as:
>
>template < unsigned long x > 
>struct argument_type< static_log2 > { 
>  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  
struct static_log2 {};

template  
struct argument_type;

template < unsigned int x > // ***
struct argument_type< static_log2 > { 
  typedef unsigned long type;
};

Yeilds:

"ComeauTest.c", line 6: error: constant "x" is not used in template argument list
  of class template "argument_type>"
 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 ***?

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

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