Re: [boost] Re: compile-time functions interface
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
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
>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
--- 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
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
>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
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