Call for interest - BOOST_AUTO_FUNCTION

I've been noticing that a lot of times in 0x code I've found it useful to create a very simple "auto function" macro that uses trailing return type syntax with decltype with 1-liner functions that automatically repeats the same expression in both the return type and the return statement. #define AUTO_FUN( name, param_list, expression ) \ auto name param_list -> decltype( expression ) { return expression; } There are two big advantages to this. The first and most obvious one is that it reduces redundancy when you have a 1-line function template which has a difficult to deduce return type that you generally would use decltype on, and the more subtle benefit is that since the exact expression is repeated in the return type you automatically get "perfect-fit" SFINAE. By that I mean it provides a quick way to SFINAE-out potential instantiations before instantiating the implementation. Because of this, even though a return type may be simple to deduce without decltype, the macro is still a valuable tool since it can cause substitution to fail if the body of a function template would fail to instantiate. You get very basic, automatic, syntax-only concept checking for free. It's a simple macro, but I find that it gets lots of use. As an example: http://codepaste.net/iqzbiz The above example is a simple "multi_cast" that chains several static_casts in a row (the example code shows a potential use-case). The subtlety here is that the return type is easily deducible without the need for decltype (the return type would just be "TargetType"). Instead, the macro is used because it causes substitution to fail if the body of the function would fail during instantiation. So when using "multi_cast" here, If someone attempts to do a cast where any of the intermediate types is not a valid conversion, rather than getting a complicated error nested inside of several instantiations, you get a single error message at the top-level call-site stating that there is no match for the function call (well, at least it's a simple to read error in gcc... *cough*). This works because if the body of any of the calls would have an error, substitution would instead fail, meaning substitution would fail for the caller, all the way back up to the top without any bodies being instantiated. In other words, it's SFINAEs all the way down :| I find this type of functionality to be very useful, particularly in libraries. In fact, I find myself using it for just about all 1-line function templates. Do others agree that this would be a worthwhile addition to boost? Documentation should be quick to write up. The macro would of course be renamed to something along the lines of BOOST_AUTO_FUNCTION If anyone thinks multi_cast would be useful, let me know and I'll also spin off a separate thread for that, though I'm tempted to think it's more of a curiosity than something that would get much use. -- -Matt Calabrese

At Tue, 5 Oct 2010 15:20:22 -0400, Matt Calabrese wrote:
I find this type of functionality to be very useful, particularly in libraries. In fact, I find myself using it for just about all 1-line function templates. Do others agree that this would be a worthwhile addition to boost? Documentation should be quick to write up. The macro would of course be renamed to something along the lines of BOOST_AUTO_FUNCTION
If anyone thinks multi_cast would be useful, let me know and I'll also spin off a separate thread for that, though I'm tempted to think it's more of a curiosity than something that would get much use.
I always imagined I'd want something like that when I started using C++0x in anger. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Tue, Oct 5, 2010 at 3:57 PM, David Abrahams <dave@boostpro.com> wrote:
I always imagined I'd want something like that when I started using C++0x in anger.
So I take it that's at least one definite interest, ha. I've also updated the code at the link to use a "better" implementation of AUTO_FUN: http://codepaste.net/iqzbiz It's now implemented as: #define AUTO_FUN_IMPL( ... ) decltype( __VA_ARGS__ ) { return __VA_ARGS__; } #define AUTO_FUN( name_and_param_list ) auto name_and_param_list-> AUTO_FUN_IMPL This is so that usage looks more like a function template definition, as seen in the example code. The use of __VA_ARGS__ is there so that people don't have to wrap their expression in an additional set of parentheses if a top-level comma is present in the expression (such as if you refer to a template with multiple arguments). 0x has variadic macros, might as well use them, albeit in an unconventional manner! -- -Matt Calabrese

On Tue, Oct 5, 2010 at 3:57 PM, David Abrahams <dave@boostpro.com> wrote:
I always imagined I'd want something like that when I started using C++0x in anger.
-- Dave Abrahams BoostPro Computing http://www.boostpro.com
The frustrating thing is that I'm pretty sure most people who first hear about auto when applied to function templates assume that it would mean something along the lines of what the macro does, and then they are disappointed to find out that that is not the case. I agree that for arbitrarily long functions with many statements and returns it would not be appropriate, but for 1-liners it seems like something that's both an extremely common case and trivial for compilers to implement. At least for me, it seems that the vast majority of the times one wants to use the function arguments when specifying the return type it is to duplicate the expression in a return statement exactly anyway. Was such an idea simply never proposed despite everyone I've talked to expecting it to be there? It wouldn't surprise me if the next standard remedied this, but at the moment that seems light years away. -- -Matt Calabrese

From: Matt Calabrese The frustrating thing is that I'm pretty sure most people who first hear about auto when applied to function templates assume that it would mean something along the lines of what the macro does, and then they are disappointed to find out that that is not the case. I agree that for arbitrarily long functions with many statements and returns it would not be appropriate, but for 1-liners it seems like something that's both an extremely common case and trivial for compilers to implement. At least for me, it seems that the vast majority of the times one wants to use the function arguments when specifying the return type it is to duplicate the expression in a return statement exactly anyway. Was such an idea simply never proposed despite everyone I've talked to expecting it to be there? It wouldn't surprise me if the next standard remedied this, but at the moment that seems light years away.
If a national body would point it out as a defect in its comments, wouldn't that be a thing small enough to fix it before the final draught? Just thinking aloud, I don't know if it sounds reasonable at this stage of standardisation process. Best regards, Robert

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Robert Kawulak Sent: Thursday, October 07, 2010 1:59 AM To: boost@lists.boost.org Subject: Re: [boost] Call for interest - BOOST_AUTO_FUNCTION
From: Matt Calabrese The frustrating thing is that I'm pretty sure most people who first hear about auto when applied to function templates assume that it would mean something along the lines of what the macro does, and then they are disappointed to find out that that is not the case. I agree that for arbitrarily long functions with many statements and returns it would not be appropriate, but for 1-liners it seems like something that's both an extremely common case and trivial for compilers to implement. At least for me, it seems that the vast majority of the times one wants to use the function arguments when specifying the return type it is to duplicate the expression in a return statement exactly anyway. Was such an idea simply never proposed despite everyone I've talked to expecting it to be there? It wouldn't surprise me if the next standard remedied this, but at the moment that seems
years away.
If a national body would point it out as a defect in its comments, wouldn't that be a thing small enough to fix it before the final draught? Just thinking aloud, I don't know if it sounds reasonable at this stage of standardisation
light process. I'm sure it is too late for this standard, but I suggest you write up your justification with code examples and submit to the WG21 committee yourself (you need to get a document number and use the customary format). http://www.open-std.org/jtc1/sc22/wg21/ (Anyone can do this - but don't hold your breath!). Meanwhile, having a macro that does something that people find useful is very persuasive that your 'feature' is needed. Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com

At Thu, 7 Oct 2010 02:59:00 +0200, Robert Kawulak wrote:
From: Matt Calabrese The frustrating thing is that I'm pretty sure most people who first hear about auto when applied to function templates assume that it would mean something along the lines of what the macro does, and then they are disappointed to find out that that is not the case. I agree that for arbitrarily long functions with many statements and returns it would not be appropriate, but for 1-liners it seems like something that's both an extremely common case and trivial for compilers to implement. At least for me, it seems that the vast majority of the times one wants to use the function arguments when specifying the return type it is to duplicate the expression in a return statement exactly anyway. Was such an idea simply never proposed despite everyone I've talked to expecting it to be there? It wouldn't surprise me if the next standard remedied this, but at the moment that seems light years away.
If a national body would point it out as a defect in its comments, wouldn't that be a thing small enough to fix it before the final draught?
I don't know. I can tell you this, though: without an NB comment it definitely won't happen. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

At Wed, 6 Oct 2010 16:12:57 -0400, Matt Calabrese wrote:
On Tue, Oct 5, 2010 at 3:57 PM, David Abrahams <dave@boostpro.com> wrote:
I always imagined I'd want something like that when I started using C++0x in anger.
-- Dave Abrahams BoostPro Computing http://www.boostpro.com
The frustrating thing is that I'm pretty sure most people who first hear about auto when applied to function templates assume that it would mean something along the lines of what the macro does, and then they are disappointed to find out that that is not the case.
Agreed; it's lame.
I agree that for arbitrarily long functions with many statements and returns it would not be appropriate, but for 1-liners it seems like something that's both an extremely common case and trivial for compilers to implement. At least for me, it seems that the vast majority of the times one wants to use the function arguments when specifying the return type it is to duplicate the expression in a return statement exactly anyway. Was such an idea simply never proposed despite everyone I've talked to expecting it to be there? It wouldn't surprise me if the next standard remedied this, but at the moment that seems light years away.
No, it was proposed. I don't remember why it was shot down. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Tue, Oct 5, 2010 at 3:20 PM, Matt Calabrese <rivorus@gmail.com> wrote:
I've been noticing that a lot of times in 0x code I've found it useful to create a very simple "auto function" macro that uses trailing return type syntax with decltype with 1-liner functions that automatically repeats the same expression in both the return type and the return statement.
#define AUTO_FUN( name, param_list, expression ) \ auto name param_list -> decltype( expression ) { return expression; }
It's very aggravating that C++-0x didn't include include a function definition syntax like this from the start. A large chunk of the functions I write are 1-liners so the problem you're describing certainly applies to me. I've been using the following syntax wherever feasible: auto f = //some lambda or De Bruijn Bind expression That solves the repetition problem, but the code looses resemblance to typical C++ at that point. Although your solution works well, I think it is incredibly inelegant when compared to a C++ language fix. Can't we solve this problem cleanly and quickly? I'd really hate to see heaps of AUTO_FUN code created while we wait 12 years for the improvement in C++ syntax. So, personally I would not like to see this in boost. I'd like to see a clean solution in all standards conforming compilers. David -- David Sankel Sankel Software www.sankelsoftware.com 585 617 4748 (Office)

On Tue, Oct 5, 2010 at 10:50 PM, David Sankel <camior@gmail.com> wrote:
Although your solution works well, I think it is incredibly inelegant when compared to a C++ language fix. Can't we solve this problem cleanly and quickly? I'd really hate to see heaps of AUTO_FUN code created while we wait 12 years for the improvement in C++ syntax.
So, personally I would not like to see this in boost. I'd like to see a clean solution in all standards conforming compilers.
David
Well we certainly agree there, however I believe such a direct language feature is too late for 0x, so that's not really an option (someone correct me if I'm wrong)? While it's upsetting that a macro hack is needed for such a feature, I don't think there's much of a choice. -- -Matt Calabrese

At Wed, 6 Oct 2010 04:35:46 -0400, Matt Calabrese wrote:
On Tue, Oct 5, 2010 at 10:50 PM, David Sankel <camior@gmail.com> wrote:
Although your solution works well, I think it is incredibly inelegant when compared to a C++ language fix. Can't we solve this problem cleanly and quickly? I'd really hate to see heaps of AUTO_FUN code created while we wait 12 years for the improvement in C++ syntax.
So, personally I would not like to see this in boost. I'd like to see a clean solution in all standards conforming compilers.
David
Well we certainly agree there, however I believe such a direct language feature is too late for 0x, so that's not really an option (someone correct me if I'm wrong)? While it's upsetting that a macro hack is needed for such a feature, I don't think there's much of a choice.
You're right. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Tue, Oct 5, 2010 at 9:20 PM, Matt Calabrese <rivorus@gmail.com> wrote:
I've been noticing that a lot of times in 0x code I've found it useful to create a very simple "auto function" macro that uses trailing return type syntax with decltype with 1-liner functions that automatically repeats the same expression in both the return type and the return statement.
#define AUTO_FUN( name, param_list, expression ) \ auto name param_list -> decltype( expression ) { return expression; }
Why not simply auto name = [&](param_list){ return expression; } ?
There are two big advantages to this. The first and most obvious one is that it reduces redundancy when you have a 1-line function template which has a difficult to deduce return type that you generally would use decltype on, and the more subtle benefit is that since the exact expression is repeated in the return type you automatically get "perfect-fit" SFINAE. By that I mean it provides a quick way to SFINAE-out potential instantiations before instantiating the implementation. Because of this, even though a return type may be simple to deduce without decltype, the macro is still a valuable tool since it can cause substitution to fail if the body of a function template would fail to instantiate. You get very basic, automatic, syntax-only concept checking for free. It's a simple macro, but I find that it gets lots of use.
I don't know if my suggestion would give sfinae, though. Yechezkel Mett

On Sun, Oct 10, 2010 at 8:02 AM, Yechezkel Mett <ymett.on.boost@gmail.com>wrote:
Why not simply
auto name = [&](param_list){ return expression; }
That doesn't work when the function itself should be a template, which is the motivating case. Please see the code example I linked -- in my macro I don't have "template< typename Param >" or something similar because that part of the code is better off to not directly be a part of the macro itself for various reasons. Refer to the multi_cast code I linked for an example of that. The point of the macro is to allow you to define a function template that can be called with arguments of an appropriate type and have the return type be deduced automatically, it should be just as capable as any other function template that you would write as in you should be able to call it with any arguments that model the corresponding concepts as opposed to specific types, it should be able to be overloaded, you should be able to explicitly specify template arguments, etc. These capabilities are not possible with 0x lambdas because they themselves cannot directly be templates (sadly). 0x lambdas do not solve all of our problems here, and, sorry for a slightly off-topic rant in my own thread, don't even solve the problem of creating unnamed function objects in general. While they provide a way to make using standard library algorithms easier to use, they fall flat when writing things such as "callable objects" for Boost.Fusion algorithms or visitors for Boost.Variant (in all but the most trivial of special cases for Boost.Fusion). For those situations you still need to write more traditional function objects, often with an operator () template and/or overloads. Trying to simulate named functions with automatically deduced return types via lambdas by using auto, while will work for trivial function objects, simply cannot work for function templates and is, IMHO, much more of a hack than using a macro that expands to precisely what is desired. Yes, resorting to macros is unfortunate, but I really don't think there is any other option here. -- -Matt Calabrese

For another use-case, here is my implementation of clone_ptr (sorry, untested, poorly commented) http://codepaste.net/gm1g15 There the "auto function" macro is used for various things. One simple case is the make_clone_ptr template at the bottom, and another useful one is for dynamic_pointer_cast (sorry it's nested in a macro), since as far as I'm aware, there is no possible non-SFINAE-based metafunction that one could write to determine if a dynamic_cast expression would be valid. -- -Matt Calabrese

Matt, I'm convinced this is something we really need and I can't imagine any argument coming about that is convincing otherwise. I'd say go ahead and make a boost proposal. It's like taking really bad medicine and leaves me with a sour resentment against the C++ standardization process which, in my opinion, is going to ensure C++'s eventual demise. David -- David Sankel Sankel Software www.sankelsoftware.com

Some updated information so you guys aren't left in the dark -- in true boost form, what started as a simple 1-line macro has evolved into a thousand line file, though it is well worth it as I've expanded the capabilities considerably. The macro now supports a very powerful concept-like "requires", explicit return types including "lazy return types" (similar to lazy_enable_if), "requires_expression" support which allows you to specify arbitrary expression requirements, and the ability to separate declarations from implementation in cases where the return type is specified explicitly. In the end, the macro not only handles automatic return type deduction but it should also be able to act as a more powerful replacement for enable_if with respect to function templates. With some further effort, additional macros could be made to work with type templates and constructors as well, in a manner a little more similar to enable_if. To see how the macro is used go here: http://codepaste.net/4u34ma <http://codepaste.net/4u34ma>As of right now variadic macros are required, however, I could easily make them optional if I always require users to put more parenthesis in particular places (I.E. surrounding the code in a "requires" regardless of whether or not there is a comma there), though I'm not certain that I wish to go this route as, as far as I'm aware, all compilers that support trailing return type also support variadic macros. So, implementing it without variadic macros may just be forcing programmers to use lisp-level amounts of parentheses for no reason. I was hoping to have everything documented and up by now, but I'm still fleshing things out. At this time I'm working on some tricks to make misuse reported in an easy-to-read manner through some fancy preprocessor tricks and static_assert/mpl assert message. After that I believe it should be done. -- -Matt Calabrese

On 16.10.2010, at 01:22, Matt Calabrese wrote:
As of right now variadic macros are required, however, I could easily make them optional if I always require users to put more parenthesis in particular places (I.E. surrounding the code in a "requires" regardless of whether or not there is a comma there), though I'm not certain that I wish to go this route as, as far as I'm aware, all compilers that support trailing return type also support variadic macros.
Well, Clang currently doesn't, but hopefully that will change soon. Sebastian

There is a link to the current implementation at the bottom of this reply if anyone wants to play with it and not read the big block of text. On Sat, Oct 16, 2010 at 9:14 AM, Sebastian Redl < sebastian.redl@getdesigned.at> wrote:
Well, Clang currently doesn't, but hopefully that will change soon.
What I meant was that all compilers which claim to support trailing return types already support variadic macros, but not necessarily the other way around. No trailing return type support is pretty much a complete show stopper for the macro anyway, so a lack of variadic macros at that point wouldn't make things any worse. Either way, I'd rather just not support compilers in this odd state of flux between current C++ and C++0x, since trying to support a compiler without variadic macros would make using the macro more complicated and would imply a breaking change to the interface should the workaround ever stop being supported, unless I were to maintain two separately named macros. Anyway, the macro as I've described is now just about done -- I need to write up some documentation and more tests, but it should be usable, though likely only in GCC. Despite it being a gigantic macro hack, I've put a lot of effort into making decent error reporting (don't try it on anything other than GCC though heh). In order to avoid the compiler spewing out a bunch of confusing errors when you misuse it, I've gotten it to detect some possible user mistakes, including what I'd imagine would be common typos (such as require or required instead or requires). As well, on macro-use error detection, the macro does what is necessary to output code up to that point in a manner that will compile without error, but then static asserts telling the user exactly what's wrong and how to fix it. Finally, it "eats" all of the further parenthesized macro invocations so you get no additional errors related to BOOST_AUTO_FUNCTION. Of course, all of this only applies if I am able to detect the problem, otherwise you will still get some messy errors. I have some ideas for future direction already that may prove to be very useful, though I likely won't implement for a little while. Probably the most useful new feature would be to allow users to specify requirements for the automatically deduced result type. For instance, you may be writing a function template where you don't write an explicit return type since you want it to be automatically deduced by the return expression, however, you still wish to require the return type to be some kind of random access iterator, or you may wish to check if the return value could be used in particular expressions (similar to requires_expression as is in the current macro). If any of these conditions aren't met, then substitution will fail and you will see a single error. All of this combined with automatic return type deduction and arbitrary expression requirements would ordinarily be very tricky to pull off in C++0x without support, but the macro would make it embarrassingly trivial. Other new features I'm considering are return_ref, return_value, and return rvalue_ref, which would augment the automatically deduced return type accordingly. For instance: template< class L, class R > BOOST_AUTO_FUNCTION( plus_eq( L& left, R const& right ) ) ( return_ref left += right ) would return a reference to left, whereas template< class L, class R > BOOST_AUTO_FUNCTION( plus_eq( L& left, R const& right ) ) ( return_value left += right ) would return left by value Unfortunately, because of the way development unfolded, I started with a design that gets increasingly more complex as I support more argument kinds (even adding requires, requires_expression, etc. made it very redundant and almost unmaintainable). Before I add anything else, I'll need to redesign it in the way I should have done from the start, but I think I'll stop for the time being anyway and add docs/more tests then request review. To see the currently disgusting hack in all its glory: http://codepaste.net/vrn9gm Again, you have been warned to only try it in GCC. Look to my earlier replies in the thread for basic usage. Let me know if there is anything blatantly wrong, which there probably is as it's barely tested at all at this point. If you want to see some of the "pretty" error reporting I put in, try making an auto function that has two or more "( requires your_condition_here )", or write "require" instead of "requires". I don't know why I'm having so much fun with this, it's really pretty sad. I'll try to clean everything up, split it up into multiple files, and get it and some docs and tests up on the sandbox in the next couple of days. -- -Matt Calabrese

At Sun, 17 Oct 2010 02:39:52 -0400, Matt Calabrese wrote:
All of this combined with automatic return type deduction and arbitrary expression requirements would ordinarily be very tricky to pull off in C++0x without support, but the macro would make it embarrassingly trivial.
I'm all for embarrassing the designers of the language feature by building macros that work better :-) Maybe, like BOOST_FOREACH, they'll turn back into language features one day. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sun, Oct 17, 2010 at 5:34 AM, David Abrahams <dave@boostpro.com> wrote:
I'm all for embarrassing the designers of the language feature by building macros that work better :-) Maybe, like BOOST_FOREACH, they'll turn back into language features one day.
Heh, perhaps in C++3x (pending it doesn't roll over to 4x). When I added the "requires" feature I looked up how "requires" would have worked in C++0x so that I could try to mimic it as closely as possible. In doing this, one thing I noticed was that you had to put your "requires" immediately after template< /**/ > and before the function name and return type. The downside of this is that it implies that you can't refer to your arguments in the predicate (I.E. sizeof( left + right ) or something similar)! Not that such uses would have been very common anyway, but BOOST_AUTO_FUNCTION doesn't suffer from that problem at all since "requires" comes after the parameter list. -- -Matt Calabrese

At Sun, 17 Oct 2010 14:34:48 -0400, Matt Calabrese wrote:
On Sun, Oct 17, 2010 at 5:34 AM, David Abrahams <dave@boostpro.com> wrote:
I'm all for embarrassing the designers of the language feature by building macros that work better :-) Maybe, like BOOST_FOREACH, they'll turn back into language features one day.
Heh, perhaps in C++3x (pending it doesn't roll over to 4x).
When I added the "requires" feature I looked up how "requires" would have worked in C++0x so that I could try to mimic it as closely as possible. In doing this, one thing I noticed was that you had to put your "requires" immediately after template< /**/ > and before the function name and return type. The downside of this is that it implies that you can't refer to your arguments in the predicate (I.E. sizeof( left + right ) or something similar)! Not that such uses would have been very common anyway
Right, you should be writing your requirements in terms of concepts if you have that facility.
but BOOST_AUTO_FUNCTION doesn't suffer from that problem at all since "requires" comes after the parameter list.
BTW, seems like you're close enough; it's probably time to integrate concept support for a future BCCL. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sun, Oct 17, 2010 at 10:27 PM, David Abrahams <dave@boostpro.com> wrote:
BTW, seems like you're close enough; it's probably time to integrate concept support for a future BCCL.
Okay, I've finished support for everything talked about up until this point (minus continue try, which is also now called auto try). I also have some exciting news (well, exciting to me at least, though I may be jumping the gun). During development of the macro, I came up with a way to emulate concept-based template overloads, and it should be possible to integrate it into the macro, making for a possible, very powerful, BCCL 2. By this I mean being able to write, for instance, a function template that is overloaded for forward iterators and another that is overloaded for random access iterators, while making it unambiguous to call with an iterator that explicitly models the random access iterator concept -- I.E. the random access iterator version will be picked as a better match, much like what you'd use tag dispatching for now and what concept-based template overloads would have done in C++ with concepts. I don't have a working implementation with the macro yet, but my "proof-of-concept" (har) seems to work like a charm, which I have included in this post. Before going further, if you aren't following what I mean, here's some hypothetical syntax that I'm fairly certain should be possible (I may be able to come up with something simpler): //////////////////////////////////////// // This is a "dispatcher" function template // It specifies which arguments are used with concept overloads // and forwards implementation to user-written overloads // based on concepts that the arguments model // "foo" is the name of the function and the part after that is a // way to specify the parameters BOOST_AUTO_FUNCTION ( ( template< class It > ) , ( foo )( (switch)(It)(iterator) ) // switch means that a given parameter participates in the concept overloading , ( explicit It ) ) // Note that switch can be used with any number of arguments // I may get rid of switch on a per-argument basis and have it be // implied for all arguments when a "switch" is present // Here is an overload that is picked when iterator models forward_iterator BOOST_AUTO_FUNCTION ( ( template< class It > ) , ( foo )( (case forward_iterator)(It)(iterator) ) , ( explicit It ) ) { // ... return iterator; } // Here is an overload that is picked when iterator models random_access_iterator BOOST_AUTO_FUNCTION ( ( template< class It > ) , ( foo )( (case random_access_iterator)(It)(iterator) ) ) { // ... return iterator; } int main() { int* it = /*some valid initialization*/; foo( it ); // Unambiguously calls the random_access_iterator version } //////////////////////////////////////// The way it works internally is via an internal tag-dispatching-based system that automatically knows all explicit concept maps associated with a given type. It sort of magic, but I believe it is completely standard. The surprisingly simple implementation trick that I use to pull this off is as follows: //////////////////////////////////////// // The max number of top-level concepts that can // be associated with a single type unsigned const top_index = 16; template< unsigned MapIndex > struct map_index : map_index< MapIndex - 1 > { static_assert( MapIndex != top_index + 1, "Too many concept maps for type" ); }; template<> struct map_index< 0 > {}; template< class ConceptMaps > struct concept_map_child_t; template< class... T > struct vector; template< class Vector, class Elem > struct push_front; template< class... T, class Elem > struct push_front< vector< T... >, Elem > { typedef vector< Elem, T... > type; }; template< class... T > struct concept_map_child_t< vector< T... > > : virtual T... { }; template< class ThisConceptMap = void, class OtherConceptMaps = void > struct concept_maps_t { static unsigned const value = OtherConceptMaps::value + 1; static map_index< value + 1 > next_index(); typedef ThisConceptMap this_concept_map; typedef typename push_front< typename OtherConceptMaps::concept_maps , this_concept_map >::type concept_maps; typedef concept_map_child_t< concept_maps > tag_t; static tag_t tag() { return tag_t(); } }; template<> struct concept_maps_t<> { static unsigned const value = 0; static map_index< 1 > next_index(); typedef vector<> concept_maps; typedef concept_map_child_t< concept_maps > tag_t; static tag_t tag() { return tag_t(); } }; template< class T > struct identity {}; template< class T > concept_maps_t<> concept_maps( T, map_index< 0 > ); // Creates a new "concept_maps" declaration that will be picked over previous ones // when passing in a given type and map_index< top_index > #define MACRO_CALLED_INTERNALLY_WHEN_MAPPING( type, concept )\ namespace{\ concept_maps_t\ < concept\ , decltype( concept_maps( identity< type >(), map_index< top_index >() ) )\
\ concept_maps\ ( identity< type >\ , decltype( concept_maps( identity< type >()\ , map_index< top_index >() ).next_index()\ )\ );\ }
//////////////////////////////////////// The purpose of the above code is to be able to automatically retrieve all concepts associated with a given type at a given point in code. To see how this would be used in practice: //////////////////////////////////////// // Dummy types used as examples to symbolize concepts struct some_concept0 {}; struct some_concept1 {}; struct some_concept2 {}; struct some_concept3 {}; // A user's hypothetical container type class some_container {}; // Internals to explicit mappings to 4 different concepts MACRO_CALLED_INTERNALLY_WHEN_MAPPING( some_container, some_concept0 ) // ... arbitrary code here... MACRO_CALLED_INTERNALLY_WHEN_MAPPING( some_container, some_concept1 ) MACRO_CALLED_INTERNALLY_WHEN_MAPPING( some_container, some_concept2 ) MACRO_CALLED_INTERNALLY_WHEN_MAPPING( some_container, some_concept3 ) // At this point we have mapped 4 separate concepts to some_container // Each concept map could appear at namespace scope anywhere in // library or user files //////////////////////////////////////// Finally, here is how everything comes together. Inside of the BOOST_AUTO_FUNCTION with the "switch" parameter from the first example, we extract a type that inherits from all of the concepts from which there are concept maps for the given type by relying on the trick shown above. We then use this type internally for tag dispatching. An example of what happens in the innards of that first function template is this (again, this is all hidden from the user and done automatically via the BOOST_AUTO_FUNCTION macro invocation): //////////////////////////////////////// typedef decltype( concept_maps( identity< some_container >(), map_index< top_index >() ) ) concepts_maps_type; typedef decltype( type_with_a_nested_static_function( concepts_maps_type::tag() ) ) fun_holder; return fun_holder::impl( std::forward< It >( iterator ) ); //////////////////////////////////////// I hope this shows my point. Using this approach we should be able to nearly fully simulate concept-based overloading for types with explicit concept maps, having all tag dispatching done in a way that is transparent to the user. With some effort, this approach could even be applied to variadic function templates. I'm fairly certain that this is all standard, but there may be the possibility for ODR violations... Another thing to consider is perhaps to not use "identity" and instead use something like "type**" for purposes of ADL. Regardless, I'm confident that this approach or a variant could be used in some way to get entirely library-based-concept-based overloads, unless someone sees a big problem. Finally, back on the topic of BOOST_AUTO_FUNCTION. At this point, conditions not met causes substitution to fail, which is extremely useful, however, it seems that many times you may want a static_assert instead. The SFINAE version is useful when you have multiple overloads with mutually exclusive conditions, whereas the static_assert version is good for a function template where you have a top-level condition that must be met regardless of overloads. For this reason, I'm likely going to add (break if some_condition) which will static_assert when the condition is met, having the text of the condition in the static_assert message. Similar behavior would exist for (break not some_condition). As a use-case, the first "foo" template (the one with the switch) could have ( break not is_forward_iterator< It > ), which would trigger a static_assert if you try to call it with something that isn't an iterator at all. Also, in case it isn't already apparent, the old use of "break" no longer exists because of the design changes talked about earlier in the thread. This would be a new use entirely. -- -Matt Calabrese

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Matt Calabrese Sent: Wednesday, October 27, 2010 4:37 PM To: boost@lists.boost.org Subject: Re: [boost] Call for interest - BOOST_AUTO_FUNCTION On Sun, Oct 17, 2010 at 10:27 PM, David Abrahams <dave@boostpro.com> wrote:
BTW, seems like you're close enough; it's probably time to integrate concept support for a future BCCL.
Okay, I've finished support for everything talked about up until this point (minus continue try, which is also now called auto try). I also have some exciting news (well, exciting to me at least, though I may be jumping the gun). During development of the macro, I came up with a way to emulate concept-based template overloads, and it should be possible to integrate it into the macro, making for a possible, very powerful, BCCL 2. By this I mean being able to write, for instance, a function template that is overloaded for forward iterators and another that is overloaded for random access iterators, while making it unambiguous to call with an iterator that explicitly models the random access iterator concept -- I.E. the random access iterator version will be picked as a better match, much like what you'd use tag dispatching for now and what concept-based template overloads would have done in C++ with concepts. I don't have a working implementation with the macro yet, but my "proof-of-concept" (har) seems to work like a charm, which I have included in this post. Before going further, if you aren't following what I mean, here's some hypothetical syntax that I'm fairly certain should be possible (I may be able to come up with something simpler): //////////////////////////////////////// // This is a "dispatcher" function template // It specifies which arguments are used with concept overloads // and forwards implementation to user-written overloads // based on concepts that the arguments model // "foo" is the name of the function and the part after that is a // way to specify the parameters BOOST_AUTO_FUNCTION ( ( template< class It > ) , ( foo )( (switch)(It)(iterator) ) // switch means that a given parameter participates in the concept overloading , ( explicit It ) ) // Note that switch can be used with any number of arguments // I may get rid of switch on a per-argument basis and have it be // implied for all arguments when a "switch" is present // Here is an overload that is picked when iterator models forward_iterator BOOST_AUTO_FUNCTION ( ( template< class It > ) , ( foo )( (case forward_iterator)(It)(iterator) ) , ( explicit It ) ) { // ... return iterator; } // Here is an overload that is picked when iterator models random_access_iterator BOOST_AUTO_FUNCTION ( ( template< class It > ) , ( foo )( (case random_access_iterator)(It)(iterator) ) ) { // ... return iterator; } int main() { int* it = /*some valid initialization*/; foo( it ); // Unambiguously calls the random_access_iterator version } //////////////////////////////////////// The way it works internally is via an internal tag-dispatching-based system that automatically knows all explicit concept maps associated with a given type. It sort of magic, but I believe it is completely standard. The surprisingly simple implementation trick that I use to pull this off is as follows: //////////////////////////////////////// // The max number of top-level concepts that can // be associated with a single type unsigned const top_index = 16; template< unsigned MapIndex > struct map_index : map_index< MapIndex - 1 > { static_assert( MapIndex != top_index + 1, "Too many concept maps for type" ); }; template<> struct map_index< 0 > {}; template< class ConceptMaps > struct concept_map_child_t; template< class... T > struct vector; template< class Vector, class Elem > struct push_front; template< class... T, class Elem > struct push_front< vector< T... >, Elem > { typedef vector< Elem, T... > type; }; template< class... T > struct concept_map_child_t< vector< T... > > : virtual T... { }; template< class ThisConceptMap = void, class OtherConceptMaps = void > struct concept_maps_t { static unsigned const value = OtherConceptMaps::value + 1; static map_index< value + 1 > next_index(); typedef ThisConceptMap this_concept_map; typedef typename push_front< typename OtherConceptMaps::concept_maps , this_concept_map >::type concept_maps; typedef concept_map_child_t< concept_maps > tag_t; static tag_t tag() { return tag_t(); } }; template<> struct concept_maps_t<> { static unsigned const value = 0; static map_index< 1 > next_index(); typedef vector<> concept_maps; typedef concept_map_child_t< concept_maps > tag_t; static tag_t tag() { return tag_t(); } }; template< class T > struct identity {}; template< class T > concept_maps_t<> concept_maps( T, map_index< 0 > ); // Creates a new "concept_maps" declaration that will be picked over previous ones // when passing in a given type and map_index< top_index > #define MACRO_CALLED_INTERNALLY_WHEN_MAPPING( type, concept )\ namespace{\ concept_maps_t\ < concept\ , decltype( concept_maps( identity< type >(), map_index< top_index >() ) )\
\ concept_maps\ ( identity< type >\ , decltype( concept_maps( identity< type >()\ , map_index< top_index >() ).next_index()\ )\ );\ }
//////////////////////////////////////// The purpose of the above code is to be able to automatically retrieve all concepts associated with a given type at a given point in code. To see how this would be used in practice: //////////////////////////////////////// // Dummy types used as examples to symbolize concepts struct some_concept0 {}; struct some_concept1 {}; struct some_concept2 {}; struct some_concept3 {}; // A user's hypothetical container type class some_container {}; // Internals to explicit mappings to 4 different concepts MACRO_CALLED_INTERNALLY_WHEN_MAPPING( some_container, some_concept0 ) // ... arbitrary code here... MACRO_CALLED_INTERNALLY_WHEN_MAPPING( some_container, some_concept1 ) MACRO_CALLED_INTERNALLY_WHEN_MAPPING( some_container, some_concept2 ) MACRO_CALLED_INTERNALLY_WHEN_MAPPING( some_container, some_concept3 ) // At this point we have mapped 4 separate concepts to some_container // Each concept map could appear at namespace scope anywhere in // library or user files //////////////////////////////////////// Finally, here is how everything comes together. Inside of the BOOST_AUTO_FUNCTION with the "switch" parameter from the first example, we extract a type that inherits from all of the concepts from which there are concept maps for the given type by relying on the trick shown above. We then use this type internally for tag dispatching. An example of what happens in the innards of that first function template is this (again, this is all hidden from the user and done automatically via the BOOST_AUTO_FUNCTION macro invocation): //////////////////////////////////////// typedef decltype( concept_maps( identity< some_container >(), map_index< top_index >() ) ) concepts_maps_type; typedef decltype( type_with_a_nested_static_function( concepts_maps_type::tag() ) ) fun_holder; return fun_holder::impl( std::forward< It >( iterator ) ); //////////////////////////////////////// I hope this shows my point. Using this approach we should be able to nearly fully simulate concept-based overloading for types with explicit concept maps, having all tag dispatching done in a way that is transparent to the user. With some effort, this approach could even be applied to variadic function templates. I'm fairly certain that this is all standard, but there may be the possibility for ODR violations... Another thing to consider is perhaps to not use "identity" and instead use something like "type**" for purposes of ADL. Regardless, I'm confident that this approach or a variant could be used in some way to get entirely library-based-concept-based overloads, unless someone sees a big problem. Finally, back on the topic of BOOST_AUTO_FUNCTION. At this point, conditions not met causes substitution to fail, which is extremely useful, however, it seems that many times you may want a static_assert instead. The SFINAE version is useful when you have multiple overloads with mutually exclusive conditions, whereas the static_assert version is good for a function template where you have a top-level condition that must be met regardless of overloads. For this reason, I'm likely going to add (break if some_condition) which will static_assert when the condition is met, having the text of the condition in the static_assert message. Similar behavior would exist for (break not some_condition). As a use-case, the first "foo" template (the one with the switch) could have ( break not is_forward_iterator< It > ), which would trigger a static_assert if you try to call it with something that isn't an iterator at all. Also, in case it isn't already apparent, the old use of "break" no longer exists because of the design changes talked about earlier in the thread. This would be a new use entirely. -- -Matt Calabrese _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost Hi, This looks quite interesting. I have a question: // The max number of top-level concepts that can // be associated with a single type unsigned const top_index = 16; template< unsigned MapIndex > struct map_index : map_index< MapIndex - 1 > { static_assert( MapIndex != top_index + 1, "Too many concept maps for type" ); }; template<> struct map_index< 0 > {}; Doesn't this declaration ("template<> struct map_index< 0 > {};") create an object that derives from map_index<-1> (except of course this is of unsigned type, so it is really std::numeric_limits<unsigned>::max())? Was this intended, as it exceeds (greatly!) the limit top_index? David

On Thu, Oct 28, 2010 at 1:43 AM, David Brownstein <dbrownstein@intrix.com>wrote:
Doesn't this declaration ("template<> struct map_index< 0 > {};") create an object that derives from map_index<-1> (except of course this is of unsigned type, so it is really std::numeric_limits<unsigned>::max())? Was this intended, as it exceeds (greatly!) the limit top_index?
That line won't create an object that derives from map_index<-1>, it's a template specialization as a terminating case so that map_index<0> doesn't inherit from anything. It's there specifically to avoid the problem you are describing. The code should work in GCC if you want to play around with it, though you'll have to use some imagination since it's just an example that the technique works. I should have probably put together an example with the iterator concepts related by inheritance to bring it a little bit closer to a practical setting, but I think you get the gist. -- -Matt Calabrese

At Wed, 27 Oct 2010 22:43:41 -0700, David Brownstein wrote:
<snip massive quote>
Hi, This looks quite interesting. I have a question:
Just a reminder to everyone to please try to avoid overquoting. Thanks, -- Dave Abrahams Boost Moderator

At Wed, 27 Oct 2010 19:36:37 -0400, Matt Calabrese wrote:
On Sun, Oct 17, 2010 at 10:27 PM, David Abrahams <dave@boostpro.com> wrote:
BTW, seems like you're close enough; it's probably time to integrate concept support for a future BCCL.
Okay, I've finished support for everything talked about up until this point (minus continue try, which is also now called auto try).
I also have some exciting news (well, exciting to me at least, though I may be jumping the gun). During development of the macro, I came up with a way to emulate concept-based template overloads, and it should be possible to integrate it into the macro, making for a possible, very powerful, BCCL 2. By this I mean being able to write, for instance, a function template that is overloaded for forward iterators and another that is overloaded for random access iterators, while making it unambiguous to call with an iterator that explicitly models the random access iterator concept -- I.E. the random access iterator version will be picked as a better match, much like what you'd use tag dispatching for now and what concept-based template overloads would have done in C++ with concepts.
No. Freakin'. Way! Dude, are you kidding me?! That is too amazing. Couple of questions: * What does an explicit concept map look like? You didn't show an example. * Can you do concept map templates (e.g. all vector<T>s model Container)? <snip all your other cool stuff> I love the "break if" thing, too :-)
which will static_assert when the condition is met, having the text of the condition in the static_assert message. Similar behavior would exist for (break not some_condition). As a use-case, the first "foo" template (the one with the switch) could have ( break not is_forward_iterator< It > ), which would trigger a static_assert if you try to call it with something that isn't an iterator at all.
Not (break if not is_forward_iterator<...>) ? ^^ -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Thu, Oct 28, 2010 at 5:43 AM, David Abrahams <dave@boostpro.com> wrote:
Dude, are you kidding me?! That is too amazing.
I'm glad other people are excited about it!
Couple of questions:
* What does an explicit concept map look like? You didn't show an example.
I haven't decided on what it will look like just yet, only the fundamental mechanism that will be used under the hood. I'll post the way to specify concept maps when I get there. One thing I'm pretty sure about is that I could make it possible to create default implementations for concept maps which you'd explicitly pull in when their definition is applicable to your type. The default maps would forward associated types from, I.E. iterator traits and directly use all operations directly. Such default maps would likely be specified via a macro interface similar to BOOST_AUTO_FUNCTION. Think something along the lines of a parameter to the macro with a keyword ID of "typename" such as (typename iterator_traits< T >::value_type value_type). The neat thing about this is that since default implementations are specified with such a macro, I can also convert the associated types and expression requirements to something that can trigger SFINAE, meaning that the macro can not only generate a default mapping, but can automatically generate a metafunction that determines if a given type meets all of the requirements that are specified. As for full-on concept maps that specify all of the complicated glue code, they will likely look not too dissimilar from simple traits classes.
* Can you do concept map templates (e.g. all vector<T>s model Container)?
Yes, I believe that should be possible and I'd also consider it a necessity for such a library. However, it may end up being tricky when something has concept maps specified for all vector<T> as well as only vector<bool>, but I haven't gotten to that road just yet. There's likely a creative solution to that problem.
Not (break if not is_forward_iterator<...>) ? ^^
The reason it's "break not" as opposed to "break if not" is because of the problem I talked about earlier -- I can do multiword parameters as long as there isn't a conflict. "break if not" would conflict with "break if". Without getting too into the implementation details, it's because the first word is concatenated with an implementation detail identifier to form a macro which is invoked, then, if it's recognized as the first word of a multi-word id it does it again, etc. The problem is, once it encounters the "if", it can't safely try a further concatenation because if "not" isn't there, there may be a token from an if condition such as a condition starting with "(" or "!" which would cause an error during preprocessor concatenation, despite the fact that the condition looks as though it should be seemingly acceptable. As a side note, I may be able to get around this limitation of conflicts in multiword IDs if I require all parameters that appear after the IDs be surrounded by parentheses, since safely checking ahead for if text is parenthesized is "possible," though hacky, but I don't want to complicate use too much just for this. Another thing to consider is that when your argument is a value, "break if not" should technically work already since "not" will be treated by your compiler there as its actual meaning. You, of course, can't rely on this with arguments that are types. Anyway, while I can't do "break if not" because it conflicts with "break if", I can do "break not if" (and similarly "if" and "not if" as opposed to "if" and "not", etc.) since there would be no conflict. In fact, I recently started doing that very thing before I dropped the final "if" to simplify implementation of the macro and because it was shorter to write out without losing functionality. But now I'm breaking my own rule by talking about the parameter ID names. -- -Matt Calabrese

On Thu, Oct 28, 2010 at 10:51 AM, Matt Calabrese <rivorus@gmail.com> wrote:
Another thing to consider is that when your argument is a value, "break if not" should technically work already since "not" will be treated by your compiler there as its actual meaning.
Okay, it's not exactly the same because the parameter ID "not" would "not" the entire parameter as though it were parenthesized, whereas the C++ "not" would have the expected (or in this case, possibly unexpected) order of operations. Actually, the more I think about it, that may lead to some subtle usage mistakes that I can't realistically check for :/ Using "not" may not be a great idea... -- -Matt Calabrese

One more question: if you are doing tag dispatching internally anyhow, might it make sense to have the dispatcher function not SFINAE'd at the top level, but instead automatically static assert the concept check in the function body? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Thu, Oct 28, 2010 at 1:37 PM, David Abrahams <dave@boostpro.com> wrote:
One more question: if you are doing tag dispatching internally anyhow, might it make sense to have the dispatcher function not SFINAE'd at the top level, but instead automatically static assert the concept check in the function body?
Yes. That's sort of the motivating case for (break if) and should be enough to do just that. Taking this a bit further, perhaps in the direction you are alluding to, a more descriptive approach for situations with concept overloads might be to make the base concept requirements for parameters able to be specified as a part of the "switch" parameter. By that I mean something such as the following for the initial "dispatching" function: BOOST_AUTO_FUNCTION ( (template< class It >) , (foo)( (switch forward_iterator)(It)(iterator) ) , (explicit It) ) This would do something like what you describe -- it would static_assert in the body with a concise message telling the user exactly what is wrong and it more directly associates the parameter with its base concept requirements prior to branching off to appropriate implementations. Concepts should also be able to be tied directly to parameter types on templates that aren't branching off. For that, the syntax could be similar only instead of the keyword "switch" I could use "for" or "catch" or even "if" again, or I could make it just automatically detected if a parameter in the parameter list is a 3-element Boost.Preprocessor sequence (well, the variadic equivalent), in which case it just assumes that the first element of the sequence is the concept if and only if "switch" isn't the first word to appear in the head element. This macro is really becoming a beast, but in a good way. It's scary to think that I'm running out of good C++ keywords to use and am already considering re-using some within the macro itself when in different contexts. -- -Matt Calabrese

Another thought that could prove interesting -- I could support a more concise syntax along the lines of the following (note the lack of "template" and any specific types being mentioned): ////////// BOOST_CONCEPT_FUNCTION ( (foo)( (forward_iterator)( it ) ) , explicit decltype( it ) ) // Or even with references BOOST_CONCEPT_FUNCTION ( (bar)( (forward_iterator&)( it ) ) , explicit decltype( it ) ) // Mix it with automatically deduced return types BOOST_CONCEPT_FUNCTION ( (bar)( (forward_iterator&)( it ) ) , ( return ++it ) ) ////////// The above macro invocations would implicitly create templates without the user having to do it manually. The idea here is that for "BOOST_CONCEPT_FUNCTION", instead of using specific types in the parameter list you'd use concepts, at least by default, and you avoid having to explicitly create template parameters. If the types are needed in the function, you can always use decltype( argument ). There are some issues here still, for instance, what if this template needs arguments for additional reasons (I.E. explicit template arguments such as with Boost.Fusion "at", though in cases like that you could always have the type instead be an MPL integral constant passed as a function argument, specified as a parameter modeling such a concept, which has the positive implications of being automatically concept checked as well as more self-documenting). Another concern is what if you need something analogous to this: ////////// template< class It > void advance( It& it, typename ::std::iterator_traits< It >::difference_type difference ); ////////// I'd have to work in syntax such as the following (which I believe may be possible to do exactly as written, with some more awful hacks): ////////// BOOST_CONCEPT_FUNCTION ( (advance)( (forward_iterator&)( it ), (concept_map_of( it )::difference_type)(difference) ) , explicit void ) ////////// The latter would be able to do everything that the former can in about the same amount of code but with concept checking on top. This is all just hypothetical but should be possible. I'm really getting too far ahead of myself now, though. -- -Matt Calabrese

The more I think about it, I can remove some of those parentheses now. For example: ////////// BOOST_CONCEPT_FUNCTION ( advance( (forward_iterator&) it, (concept_map_of(it)::difference_type) difference ) , ( explicit void ) ); ////////// And it's back to looking at least a little bit more like a function declaration. I'm going to stop replying to myself, there are too many little things I keep thinking about that I probably won't be able to implement for months anyway. I'm just really thrilled about this for some reason. -- -Matt Calabrese

At Fri, 15 Oct 2010 19:22:16 -0400, Matt Calabrese wrote:
To see how the macro is used go here: http://codepaste.net/4u34ma
Nice!! Now are you ready to write BOOST_PARAMETER_AUTO_FUNCTION? :-)
<http://codepaste.net/4u34ma>As of right now variadic macros are required, however, I could easily make them optional if I always require users to put more parenthesis in particular places (I.E. surrounding the code in a "requires" regardless of whether or not there is a comma there), though I'm not certain that I wish to go this route as, as far as I'm aware, all compilers that support trailing return type also support variadic macros.
Yeah, and C99 preprocessor is required for C++0x, so I wouldn't bother.
So, implementing it without variadic macros may just be forcing programmers to use lisp-level amounts of parentheses for no reason.
Yep.
I was hoping to have everything documented and up by now, but I'm still fleshing things out. At this time I'm working on some tricks to make misuse reported in an easy-to-read manner through some fancy preprocessor tricks and static_assert/mpl assert message. After that I believe it should be done.
This is very cool. Questions * The "keywords" are getting a bit long. Could you think of shorter names? Super bonus for finding a way to make them highlight distinctively ;-) * is it possible to make all return types lazily computed, so there's no need for lazy_result_type? I'm not saying I see how to do this, but you might :-) * What is (end) and where is it needed? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sun, Oct 17, 2010 at 5:32 AM, David Abrahams <dave@boostpro.com> wrote:
At Fri, 15 Oct 2010 19:22:16 -0400, Matt Calabrese wrote:
To see how the macro is used go here: http://codepaste.net/4u34ma
Nice!! Now are you ready to write BOOST_PARAMETER_AUTO_FUNCTION? :-)
Ha. You know, I actually considered using Boost.Parameter internally for its type template features before opting for just specializations, but for some reason I never even thought of trying to support Boost.Paramter functions. Perhaps for release 10 :p On Sun, Oct 17, 2010 at 5:32 AM, David Abrahams <dave@boostpro.com> wrote:
Questions
* The "keywords" are getting a bit long. Could you think of shorter names? Super bonus for finding a way to make them highlight distinctively ;-)
I could certainly change requires_expression to requires_expr or anything else that makes sense. I'm not tied to anything in particular When you say highlight, do you mean try to reuse more C++ keywords so they highlight in IDEs, something like I do with "return" (and I guess "requires" if C++ were to eventually get concepts)? I could use "break" instead of "end". "explicit" might make sense for explicitly specifying the return type as opposed to "result_type", though I feel like the latter may be more clear. Maybe I could use "if" instead of "requires". If you have any other suggestions, let me know. I'm all for something like that as long as the keywords make sense.
* is it possible to make all return types lazily computed, so there's no need for lazy_result_type? I'm not saying I see how to do this, but you might :-)
Definitely. I could make it work like mpl::apply (I think that's a feature of apply unless I'm mistaken) and just use ::type if its there, otherwise use the type itself. In the code right now I implement result_type with lazy_result_type anyway by wrapping it in mpl::identity.
* What is (end) and where is it needed?
Ah, yeah, I should have been more clear on that. Perhaps I'll make a more descriptive error message if you misuse it. "end" is required when you want to end a function header such as to either separate the declaration from the implementation, or to use the macro with a multi-line function. You can only use it if you have explicitly specified a return type. You can't use it after a "return", but rather, you use it instead of return. If you declare a function with "end" you must also define it with "end", otherwise your declaration will be for a different function than your definition (ouch!). One reason why you may wish to use "end" even when you're not separating declaration from implementation is if you are using BOOST_AUTO_FUNCTION only for "requires" or "requires_expression" rather than automatic return type deduction, and it's difficult to convert your function template to a 1-liner. If that was confusing, I assure you I'll try to explain it better in the docs. -- -Matt Calabrese

At Sun, 17 Oct 2010 14:16:51 -0400, Matt Calabrese wrote:
On Sun, Oct 17, 2010 at 5:32 AM, David Abrahams <dave@boostpro.com> wrote:
At Fri, 15 Oct 2010 19:22:16 -0400, Matt Calabrese wrote:
To see how the macro is used go here: http://codepaste.net/4u34ma
Nice!! Now are you ready to write BOOST_PARAMETER_AUTO_FUNCTION? :-)
Ha. You know, I actually considered using Boost.Parameter internally for its type template features before opting for just specializations, but for some reason I never even thought of trying to support Boost.Paramter functions. Perhaps for release 10 :p
On Sun, Oct 17, 2010 at 5:32 AM, David Abrahams <dave@boostpro.com> wrote:
Questions
* The "keywords" are getting a bit long. Could you think of shorter names? Super bonus for finding a way to make them highlight distinctively ;-)
I could certainly change requires_expression to requires_expr or anything else that makes sense. I'm not tied to anything in particular
When you say highlight, do you mean try to reuse more C++ keywords so they highlight in IDEs, something like I do with "return" (and I guess "requires" if C++ were to eventually get concepts)?
Something like that.
I could use "break" instead of "end". "explicit" might make sense for explicitly specifying the return type as opposed to "result_type", though I feel like the latter may be more clear. Maybe I could use "if" instead of "requires". If you have any other suggestions, let me know. I'm all for something like that as long as the keywords make sense.
Worth trying, all of them.
* is it possible to make all return types lazily computed, so there's no need for lazy_result_type? I'm not saying I see how to do this, but you might :-)
Definitely. I could make it work like mpl::apply (I think that's a feature of apply unless I'm mistaken) and just use ::type if its there, otherwise use the type itself.
But then, how would you return something that happens to have a nested ::type? Wrap it in identity?
In the code right now I implement result_type with lazy_result_type anyway by wrapping it in mpl::identity.
* What is (end) and where is it needed?
Ah, yeah, I should have been more clear on that. Perhaps I'll make a more descriptive error message if you misuse it. "end" is required when you want to end a function header such as to either separate the declaration from the implementation, or to use the macro with a multi-line function. You can only use it if you have explicitly specified a return type. You can't use it after a "return", but rather, you use it instead of return. If you declare a function with "end" you must also define it with "end", otherwise your declaration will be for a different function than your definition (ouch!). One reason why you may wish to use "end" even when you're not separating declaration from implementation is if you are using BOOST_AUTO_FUNCTION only for "requires" or "requires_expression" rather than automatic return type deduction, and it's difficult to convert your function template to a 1-liner.
Can't you just detect whether "return" was used, and if not, sythesize the "end" internally? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sun, Oct 17, 2010 at 10:25 PM, David Abrahams <dave@boostpro.com> wrote:
But then, how would you return something that happens to have a nested ::type? Wrap it in identity?
Yes. Not that this would necessarily be a good idea, just throwing it out there. Ultimately I think it'd be best to leave it as result_type and lazy_result_type (or possibly explicit and lazy_explicit) to avoid such subtleties.
Can't you just detect whether "return" was used, and if not, sythesize the "end" internally?
No. The problem is that end is what closes off the return type (it closes off a decltype). With each ( requires stuff_here ) or similar, it adds more to the return type and then the last thing it does is specify the name of a macro. The next ( arguments_here ) applies that macro and does the same thing. At a return, everything is closed off and a definition is provided, which is why you don't need an end there, but you can't do that otherwise since it's possible that more arguments will be passed. The macro can't know in advance the next thing the user will pass -- it could be a semicolon, or it could be a return, or it could be a requires, or something else. -- -Matt Calabrese

On Mon, Oct 18, 2010 at 12:47 AM, Matt Calabrese <rivorus@gmail.com> wrote:
Can't you just detect whether "return" was used, and if not, sythesize
the "end" internally?
No. The problem is that end is what closes off the return type (it closes off a decltype). With each ( requires stuff_here ) or similar, it adds more to the return type and then the last thing it does is specify the name of a macro. The next ( arguments_here ) applies that macro and does the same thing. At a return, everything is closed off and a definition is provided, which is why you don't need an end there, but you can't do that otherwise since it's possible that more arguments will be passed. The macro can't know in advance the next thing the user will pass -- it could be a semicolon, or it could be a return, or it could be a requires, or something else.
-- -Matt Calabrese
I could change the way the macro works by making it one single macro invocation. That's probably the better solution even though it was something I originally wanted to avoid. Not having to put "end" is a good enough reason for me to change the design. -- -Matt Calabrese

On Mon, Oct 18, 2010 at 4:41 AM, Matt Calabrese <rivorus@gmail.com> wrote:
I could change the way the macro works by making it one single macro invocation. That's probably the better solution even though it was something I originally wanted to avoid. Not having to put "end" is a good enough reason for me to change the design.
-- -Matt Calabrese
Sorry for the triple reply. Even though it's not a difficult change, I'm torn. My gripe with making it one macro is it implies extra surrounding parentheses and simply looks a bit more cluttered and confusing. That sounds like it's not a big deal, which it may not be, but it does at the very least make the original use-case more complicated. After all, the reason it was called "auto function" to begin with is because its original intent was to deduce the return type. If you separate the declaration from implementation, the return type isn't even deducible anymore, so it seems at least somewhat questionable to change the design to support such a feature. For instance template< typename T > BOOST_AUTO_FUNCTION( foo( T arg ) ) ( ( if is_integral< T > ) ( return arg + 1 )) as opposed to template< typename T > BOOST_AUTO_FUNCTION( foo( T arg ) ) ( if is_integral< T >) ( return arg + 1 ) The first one, at least to me, seems more complicated and less resembles a function. It's true that "break" is one more thing to know, but making the entire thing one macro invocation makes the original use-case -- automatically deduced return types -- more complicated. I could always just make a 2nd macro which puts everything into a single invocation without requiring "break" by just implementing it in terms of my current macro. Then I could expose them both and let users decide what they want. Either way, it should be easy to implement the changed design on top of the current design by wrapping, but not the other way around, so I think I'll just continue on as I am now and figure things out later. -- -Matt Calabrese

On Mon, Oct 18, 2010 at 6:29 PM, Matt Calabrese <rivorus@gmail.com> wrote:
Sorry for the triple reply. Even though it's not a difficult change, I'm torn. My gripe with making it one macro is it implies extra surrounding parentheses and simply looks a bit more cluttered and confusing.
I'm jumping in at the middle here, so pardon my questions/interjection. I would like to say that the parentheses don't bother me, that's already the case with Boost.Concept_check's macro system, and is something that can be addressed by documentation and (lots) of examples.
That sounds like it's not a big deal, which it may not be, but it does at the very least make the original use-case more complicated.
I don't see it that way. You're addressing a problem that could very well still be addressed by the language designers -- this macro would only be useful in case the standard doesn't change. Now say the standard doesn't get changed to support what you're proposing (I really hope you'll write the N**** paper so that the C++ committee members can address your concern and the (now in hindsight) obvious mistake), the use case you intend to enable deserves enough attention. Additional expressive power in the form of an additional set of parentheses is hardly an issue IMO.
After all, the reason it was called "auto function" to begin with is because its original intent was to deduce the return type. If you separate the declaration from implementation, the return type isn't even deducible anymore, so it seems at least somewhat questionable to change the design to support such a feature. For instance
template< typename T > BOOST_AUTO_FUNCTION( foo( T arg ) ) ( ( if is_integral< T > ) ( return arg + 1 ))
as opposed to
template< typename T > BOOST_AUTO_FUNCTION( foo( T arg ) ) ( if is_integral< T >) ( return arg + 1 )
The first one, at least to me, seems more complicated and less resembles a function.
Well, I'd like to say that the first version makes more sense to me, because I know that the requirements and the body go together -- that is, the requirements might not even be there to begin with, so the extra parentheses won't be required IIUC.
It's true that "break" is one more thing to know, but making the entire thing one macro invocation makes the original use-case -- automatically deduced return types -- more complicated.
I could always just make a 2nd macro which puts everything into a single invocation without requiring "break" by just implementing it in terms of my current macro. Then I could expose them both and let users decide what they want.
Either way, it should be easy to implement the changed design on top of the current design by wrapping, but not the other way around, so I think I'll just continue on as I am now and figure things out later.
I'd like to encourage you to keep it to one macro and let the users learn the extra parentheses required. This is the case with Boost.Concept_check and I don't complain much about that -- although I'm also the guy who likes Common Lisp and Haskell, so I might be biased to either having more parentheses or none at all and not so much whatever is in between these extremes. :D -- Dean Michael Berris deanberris.com

At Mon, 18 Oct 2010 18:45:24 +0800, Dean Michael Berris wrote:
Now say the standard doesn't get changed to support what you're proposing (I really hope you'll write the N**** paper so that the C++ committee members can address your concern and the (now in hindsight) obvious mistake), the use case you intend to enable deserves enough attention.
FWIW, I seriously doubt this result is from lack of attention. Much more likely it's due to "implementability concerns." Understanding that could be important to writing a convincing paper. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Mon, Oct 18, 2010 at 9:55 PM, David Abrahams <dave@boostpro.com> wrote:
At Mon, 18 Oct 2010 18:45:24 +0800, Dean Michael Berris wrote:
Now say the standard doesn't get changed to support what you're proposing (I really hope you'll write the N**** paper so that the C++ committee members can address your concern and the (now in hindsight) obvious mistake), the use case you intend to enable deserves enough attention.
FWIW, I seriously doubt this result is from lack of attention. Much more likely it's due to "implementability concerns." Understanding that could be important to writing a convincing paper.
Does it help the argument for a change if a macro can do the job? I mean, what can a preprocessor macro do that the compiler can't built-in from the front-end? :D I also doubt the committee members weren't paying attention. The standard is already huge as it is and diving deep into the details (and the aesthetics) of the implementation of one specific feature is time and effort consuming. I really hope it's not yet beyond repair at this point. :) -- Dean Michael Berris deanberris.com

On 18 Oct 2010, at 15:17, Dean Michael Berris wrote:
On Mon, Oct 18, 2010 at 9:55 PM, David Abrahams <dave@boostpro.com> wrote:
At Mon, 18 Oct 2010 18:45:24 +0800, Dean Michael Berris wrote:
Now say the standard doesn't get changed to support what you're proposing (I really hope you'll write the N**** paper so that the C++ committee members can address your concern and the (now in hindsight) obvious mistake), the use case you intend to enable deserves enough attention.
FWIW, I seriously doubt this result is from lack of attention. Much more likely it's due to "implementability concerns." Understanding that could be important to writing a convincing paper.
Does it help the argument for a change if a macro can do the job? I mean, what can a preprocessor macro do that the compiler can't built-in from the front-end? :D
I also doubt the committee members weren't paying attention. The standard is already huge as it is and diving deep into the details (and the aesthetics) of the implementation of one specific feature is time and effort consuming.
One big problem is probably the lack of implementations until very late in the process. rvalue references for example had complete implementations, with libraries, several years ago. This allowed us to find one really nasty issue (lvalues binding to rvalue references) and change it, due to practical experience of usage. Chris

On Mon, Oct 18, 2010 at 10:54 PM, Christopher Jefferson <chris@bubblescope.net> wrote:
On 18 Oct 2010, at 15:17, Dean Michael Berris wrote:
I also doubt the committee members weren't paying attention. The standard is already huge as it is and diving deep into the details (and the aesthetics) of the implementation of one specific feature is time and effort consuming.
One big problem is probably the lack of implementations until very late in the process.
I'd agree with this.
rvalue references for example had complete implementations, with libraries, several years ago. This allowed us to find one really nasty issue (lvalues binding to rvalue references) and change it, due to practical experience of usage.
Yeah. Although sometimes I hope C++ would have a steadier pace of evolution similar to what Python and Ruby (and dare I say it, Java) have in place. These languages are of course aren't ISO standards but hey I can keep dreaming that would happen with C++ right? :D -- Dean Michael Berris deanberris.com

At Mon, 18 Oct 2010 22:17:25 +0800, Dean Michael Berris wrote:
On Mon, Oct 18, 2010 at 9:55 PM, David Abrahams <dave@boostpro.com> wrote:
At Mon, 18 Oct 2010 18:45:24 +0800, Dean Michael Berris wrote:
Now say the standard doesn't get changed to support what you're proposing (I really hope you'll write the N**** paper so that the C++ committee members can address your concern and the (now in hindsight) obvious mistake), the use case you intend to enable deserves enough attention.
FWIW, I seriously doubt this result is from lack of attention. Much more likely it's due to "implementability concerns." Understanding that could be important to writing a convincing paper.
Does it help the argument for a change if a macro can do the job?
Maybe; I don't know.
I mean, what can a preprocessor macro do that the compiler can't built-in from the front-end? :D
“Look ahead” without processing the code semantically. “Implementability” is not a question of whether it can be implemented at all, but of whether it can be implemented reasonably within the architecture of existing compilers. If it requires a ground-up redesign of some major compiler, it's effectively unimplementable.
I also doubt the committee members weren't paying attention. The standard is already huge as it is and diving deep into the details (and the aesthetics) of the implementation of one specific feature is time and effort consuming.
I really hope it's not yet beyond repair at this point. :)
I wouldn't hold out much hope that this can happen for C++0x, unless you can convince some national body that it's so important that the standard should be rejected if they don't get it. That's what happened for exception-safety. But that sort of thing is rare. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Mon, Oct 18, 2010 at 11:14 PM, David Abrahams <dave@boostpro.com> wrote:
At Mon, 18 Oct 2010 22:17:25 +0800, Dean Michael Berris wrote:
Does it help the argument for a change if a macro can do the job?
Maybe; I don't know.
Worth a shot then. :)
I mean, what can a preprocessor macro do that the compiler can't built-in from the front-end? :D
“Look ahead” without processing the code semantically.
Ah. Hmmm... that's a tough one. But then how does the compiler do something like deduce the return type of a lambda? auto f = [](int x) { return x * 2; } Shouldn't the same mechanism be available in normal function declarations even without the computation of the return type? I would love to be able to write functions that look like: auto f(int x) { return x * 2; } This does mean though that the auto function without a trailing return type cannot be 'extern' -- and would most likely behave like a template function. Anyway, I think that suggestion wasn't well thought out but I'm throwing it out there anyway.
“Implementability” is not a question of whether it can be implemented at all, but of whether it can be implemented reasonably within the architecture of existing compilers. If it requires a ground-up redesign of some major compiler, it's effectively unimplementable.
Right, because that would mean C++0x is not an incremental change to C++03. Understood.
I also doubt the committee members weren't paying attention. The standard is already huge as it is and diving deep into the details (and the aesthetics) of the implementation of one specific feature is time and effort consuming.
I really hope it's not yet beyond repair at this point. :)
I wouldn't hold out much hope that this can happen for C++0x, unless you can convince some national body that it's so important that the standard should be rejected if they don't get it. That's what happened for exception-safety. But that sort of thing is rare.
Yeah, well in the worst case Boost would have a library pending for review (I assume) that does offer the ability to write one-liner functions with trailing return types through a preprocessor macro. Not that bad IMO, maybe it can be made part of C++1x. :) -- Dean Michael Berris deanberris.com

On Mon, Oct 18, 2010 at 12:25 PM, Dean Michael Berris < mikhailberis@gmail.com> wrote:
But then how does the compiler do something like deduce the return type of a lambda?
auto f = [](int x) { return x * 2; }
Shouldn't the same mechanism be available in normal function declarations even without the computation of the return type? I would love to be able to write functions that look like:
auto f(int x) { return x * 2; }
Ah! This just made me realize that it should be possible (and easy) with the macro to support multi-line void functions much like lambdas do. What I'm proposing is that I support syntax something along the lines of this: template< typename T > BOOST_AUTO_FUNCTION( ( foo( T& arg ) ) ( do // "do" is just the parameter ID like "requires" and "return" ++arg; std::cout << arg; // Do as much stuff as you want )) It would be implemented by internally doing something similar to this: auto foo( T& arg ) -> decltype( [&] { ++arg; std::cout << arg; // Do as much stuff as you want }() ) { return [&] { ++arg; std::cout << arg; // Do as much stuff as you want }(); } That should work, correct? 1-line functions should get the properly deduced return type still, but now multi-line void functions are supported in the exact way that they are with respect to lambdas. Since the multi-line function would be void, the main benefit of this would be that since the statements all appear in the return type of the encapsulating function, definitions that would fail to instantiate are now caught by SFINAE (someone correct me if I'm wrong here, I'm not certain off-hand that the extended SFINAE rules apply to statements in a lambda function). Does anyone see something that I am missing? This should probably work, correct? I'm also not sure that "do" would be a good idea to use in this context, as it may end up being confusing. -- -Matt Calabrese

At Mon, 18 Oct 2010 17:55:44 -0400, Matt Calabrese wrote:
What I'm proposing is that I support syntax something along the lines of this:
template< typename T > BOOST_AUTO_FUNCTION( ( foo( T& arg ) ) ( do // "do" is just the parameter ID like "requires" and "return" ++arg; std::cout << arg; // Do as much stuff as you want ))
Yeah, but the prospect of seeing "do do" in my code isn't very appetizing to me template< typename T > BOOST_AUTO_FUNCTION( ( foo( T& arg ) ) ( do do { ++arg; } while(arg < 0); )) but I guess that's not very likely ;-)
I'm also not sure that "do" would be a good idea to use in this context, as it may end up being confusing.
or... embarrassing ;-) -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Mon, Oct 18, 2010 at 5:55 PM, Matt Calabrese <rivorus@gmail.com> wrote:
It would be implemented by internally doing something similar to this:
auto foo( T& arg ) -> decltype( [&] { ++arg; std::cout << arg; // Do as much stuff as you want }() ) { return [&] { ++arg; std::cout << arg; // Do as much stuff as you want }(); }
Can someone using VC++ or any compiler that claims to support lambdas test this out? GCC can't compile it all -- I'm curious if anything can yet. Also, here are the new parameter IDs -- I've made them all keywords as per Dave's suggestion: what were "result_type" and "lazy_result_type" are now both just "explicit" which is always lazy and yields the type being passed if it doesn't have a ::type (this may change). what was "requires" is now "if" what was "requires_not" is now simply "not" what was "requires_expression" is now "try" what was requires_expressions" is also now "try" (try always takes a preprocessor sequence of expressions now) "return" is still "return", however it will likely be changed to use the lambda function trick meaning that you can include a semicolon (the semicolon can be optional since I could add one inside the macro -- if the user provided one it'd just be an empty statement at the end of the function, otherwise it would end the return statement). This is good because if the lambda version doesn't work on your compiler, I can just use the old implementation and you'd still be able to use "return", though you'd be required to not end it with a semicolon. For maximum portability you'd just never use a semicolon for the time being. Hopefully this shouldn't be an issue for too long anyway, but I wouldn't get my hopes up. I'll likely use "do" for the multi-line trick. I haven't yet decided what I'd use for the eventually-to-be-implemented checking of return type requirements. Possibly "catch" but that's sort of a stretch. Another possibility might be something like the two word ID "continue if". If you want to suggest IDs, two word IDs should be fine as long as the first word in the phrase isn't already used as a 1-word ID. For instance "continue if" and "continue not" together are unambiguous, but "if continue" would not be okay because I wouldn't be able to know if I should look ahead or not after the "if" (and erroneously looking ahead would have unpredictable behavior -- most-likely an odd compile error). -- -Matt Calabrese

On 10/18/2010 6:10 PM, Matt Calabrese wrote:
On Mon, Oct 18, 2010 at 5:55 PM, Matt Calabrese<rivorus@gmail.com> wrote: [...] what was "requires" is now "if"
what was "requires_not" is now simply "not" [...]
Using "if" and "not" for opposite things seems kind of awkward...maybe "if" and "unless" ? I haven't been following *too* closely on this, but it does look useful. - Jeff

On Mon, Oct 18, 2010 at 10:27 PM, Jeffrey Lee Hellrung, Jr. < jhellrung@ucla.edu> wrote:
Using "if" and "not" for opposite things seems kind of awkward...maybe "if" and "unless" ?
Yeah, I admit I do like unless better, but we're trying to go for C++ keywords since they highlight in IDEs. -- -Matt Calabrese

On 10/18/2010 9:00 PM, Matt Calabrese wrote:
On Mon, Oct 18, 2010 at 10:27 PM, Jeffrey Lee Hellrung, Jr.< jhellrung@ucla.edu> wrote:
Using "if" and "not" for opposite things seems kind of awkward...maybe "if" and "unless" ?
Yeah, I admit I do like unless better, but we're trying to go for C++ keywords since they highlight in IDEs.
Whichever keywords you choose is ultimately up to you, but, generally speaking, "such-and-such syntax-highlights better in IDEs" doesn't seem like a good rationale to base interface and designed decisions of any kind on. I'll leave it at that though. - Jeff

On Tue, Oct 19, 2010 at 1:10 AM, Jeffrey Lee Hellrung, Jr. < jhellrung@ucla.edu> wrote:
Whichever keywords you choose is ultimately up to you, but, generally speaking, "such-and-such syntax-highlights better in IDEs" doesn't seem like a good rationale to base interface and designed decisions of any kind on. I'll leave it at that though.
Just goes to show that you can't please everyone. Keep in mind they weren't keywords at the start of this thread, it was a suggestion. The rationale for reusing keywords are that they are one less thing for users to remember and they highlight if you spell them correctly (macros like this tend to blow up in your face if you happen to misspell something, so this is actually a very good thing). "if" and "not" will highlight in C++ IDEs because they are C++ keywords meaning users will know when they get it right. "unless" does not have that advantage. If highlighting weren't an issue, I'd likely still be using "requires" rather than "if", but I decided on "if" because requires isn't a keyword (yet) and therefore doesn't highlight. When trying to remember which parameter ID to use, it's not much of a stretch at all to think that users may misremember "requires" as "require" or "required" or something similar, but their IDE won't be able to help them out. The same goes for "requires_expression". Such problems don't exist when the IDs being used are "if" and "try". Since all of the other Parameter IDs are keywords, I'd rather have "not" over "unless" for consistency's sake more than anything else. Anyway, "not" is just there for convenience anyway, kind of like what disable_if is to enable_if. I'm not even sure it will be there in the end as it is functionally no different from just wrapping your metafunction in mpl::not_ or doing !your_metafunction::value. I'm getting tired and annoyed by this discussion, not to anyone's fault, it's just getting a bit silly (poop jokes aside). Personally, I don't really care what the exact names are as long as they make sense and are easy to remember. Everyone will have their opinion one way or the other and I'm just going to draw the line here. No more name changes. All of these details can be worked out after I submit it for review, and at that point, pending it even gets accepted, if there is a strong opinion in one direction I will make changes, but as of right now I'd rather just get back to focusing on functionality. -- -Matt Calabrese

On Tue, Oct 19, 2010 at 3:34 AM, Matt Calabrese <rivorus@gmail.com> wrote:
All of these details can be worked out after I submit it for review, and at that point, pending it even gets accepted, if there is a strong opinion in one direction I will make changes, but as of right now I'd rather just get back to focusing on functionality.
Alright, I have an interesting way to handle checking arbitrary expression requirements for the automatically deduced result type, but I'm not sure it's standard.:It's actually kind of nasty, but I think it would work and it also has the side-effect of allowing users to pass a series of statements, including declarations, to "try" and "continue try", instead of a preprocessor sequence of expressions (though compilers can't handle it yet). For a macro invocation such as this: template< class T > BOOST_AUTO_FUNCTION( (foo( T arg )) , ( continue try some_required_function( _result_() ); some_other_function( _result_() ); ) , ( return arg + 1; ) ) It would generate code where something such as the following would appear at some point in the return type, for purposes of SFINAE: decltype( [&]( decltype( [&]{ return arg; }() ) (*_result_)() ){ some_required_function( _result_() )); some_other_function( _result_() );; } ) That's a mouthful, I know, but essentially what's happening is I'm creating a lambda that has a function pointer parameter called "_result_" with a return type that matches that of the "auto function", and in the body of that lamda function it simply repeats the arguments passed to "continue try". The reason why _result_ is a function pointer that is invoked as opposed to simply a parameter whose type is a reference to the result type is because doing that would force the value to be an lvalue when used in expressions. By making _result_ a function pointer to be called, we can be certain that its use in tested expressions has exactly the properties as that of using the result type of the "auto function". If the user wishes to test the result as if it were an lvalue, he'd either create a declaration, or I could simply add a second parameter to the lambda function called "_lvalue_result_" whose type is a reference to the result type of the "auto function". It's pretty gross, but I think it might be standard. It won't be implemented for a while though, as I have no way to test it. -- -Matt Calabrese

On Wed, Oct 20, 2010 at 4:51 PM, Matt Calabrese <rivorus@gmail.com> wrote:
On Tue, Oct 19, 2010 at 3:34 AM, Matt Calabrese <rivorus@gmail.com> wrote:
All of these details can be worked out after I submit it for review, and at that point, pending it even gets accepted, if there is a strong opinion in one direction I will make changes, but as of right now I'd rather just get back to focusing on functionality.
Alright, I have an interesting way to handle checking arbitrary expression requirements for the automatically deduced result type, but I'm not sure it's standard.:It's actually kind of nasty, but I think it would work and it also has the side-effect of allowing users to pass a series of statements, including declarations, to "try" and "continue try", instead of a preprocessor sequence of expressions (though compilers can't handle it yet).
It also just occurred to me that if this solution works there is no need to separate "if" from "continue if", and "try" from "continue try". -- -Matt Calabrese

On Mon, Oct 18, 2010 at 6:45 AM, Dean Michael Berris <mikhailberis@gmail.com
wrote:
On Mon, Oct 18, 2010 at 6:29 PM, Matt Calabrese <rivorus@gmail.com> wrote:
Sorry for the triple reply. Even though it's not a difficult change, I'm torn. My gripe with making it one macro is it implies extra surrounding parentheses and simply looks a bit more cluttered and confusing.
I'm jumping in at the middle here, so pardon my questions/interjection.
No need to apologize. I'd much rather more people than fewer give their opinion here. On Mon, Oct 18, 2010 at 6:45 AM, Dean Michael Berris <mikhailberis@gmail.com
wrote:
I would like to say that the parentheses don't bother me, that's already the case with Boost.Concept_check's macro system, and is something that can be addressed by documentation and (lots) of examples.
That is true, however, documentation and examples also make the current approach easy to work with and, at least in my opinion, it's simpler for many use-cases (though at 2:1 I'm looking to be the minority here).
On Mon, Oct 18, 2010 at 6:45 AM, Dean Michael Berris < mikhailberis@gmail.com> wrote: You're addressing a problem that could very well still be addressed by the language designers -- this macro would only be useful in case the standard doesn't change.
Ah, yeah! That's it. It would definitely be much more feasible to have the 1-macro version implementation be changed to just transform the arguments to whatever the standard defines as the proper syntax. With my current approach, that is potentially not possible (I.E. requirements must come before the function name). I'm convinced for real now, I'll switch over to a 1 macro version. -- -Matt Calabrese
participants (11)
-
Christopher Jefferson
-
David Abrahams
-
David Brownstein
-
David Sankel
-
Dean Michael Berris
-
Jeffrey Lee Hellrung, Jr.
-
Matt Calabrese
-
Paul A. Bristow
-
Robert Kawulak
-
Sebastian Redl
-
Yechezkel Mett