
Hi Dan & Joel,
Tobias Schwinger wrote:
(It would also be cool if one could just typedef the lambda expression to nested result or inherit from a wrapper. I don't know whether it's possible and a good idea - this part is just loud thinking)...
// rtc stands for runtime code
struct a_func : result< munch< _1, tweak<_2> > > { template<typename A, typename B> typename result<A,B>::type operator()(A const & a, B const & b) const { return rtc::munch(a,rtc::tweak(b)); } };
Here's an implementation. I changed the name from 'result' to 'lambda' (because nested classes shouldn't have the same name as the enclosing ones). FILES: ====== o lambda.hpp MPL-lambda adapter for result computation o lambda_test.cpp test/example for MPL-lambda adapter TESTED WITH: ============ o GCC 3.4.2 o MSVC 8.0 o MSVC 7.1 It works really well -- the technique also reduces ambiguity problems caused by ADL with mutliple namespaces! Hope you like it as much as I do... Regards, Tobias // (C) Copyright Tobias Schwinger // // Use modification and distribution are subject to the boost Software License, // Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt). //------------------------------------------------------------------------------ #include <boost/type.hpp> #include <boost/fusion/algorithm/transformation/transform.hpp> #include <boost/fusion/sequence/container/vector.hpp> #include <boost/fusion/sequence/generation/make_vector.hpp> #include <boost/fusion/support/lambda.hpp> // namespace setup namespace rmf // result metafunctions { using namespace boost::fusion::result_of; using namespace boost::mpl::placeholders; using boost::add_const; } namespace rtc // runtime code { using namespace boost::fusion; } // ---- transform function namespace rmf { typedef lambda< boost::type<_> > a_transform_op; } namespace rtc { using namespace boost::mpl::placeholders; struct a_transform_op : rmf::a_transform_op { template<typename T> typename result<T>::type operator()(T const &) const { return boost::type<T>(); } }; } // ---- user defined algorithm built on top of fusion::transform namespace rmf { typedef lambda< transform<add_const<_>, rtc::a_transform_op> > a_transform; } namespace rtc { template<typename Seq> typename rmf::a_transform::template result<Seq>::type inline a_transform(Seq const & seq) { return rtc::transform(seq, a_transform_op()); // qualification pleases gcc } void test() { a_transform(make_vector("hi","there")); } } // (C) Copyright Tobias Schwinger // // Use modification and distribution are subject to the boost Software License, // Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt). //------------------------------------------------------------------------------ #ifndef BOOST_FUSION_LAMBDA_HPP_INCLUDED #define BOOST_FUSION_LABBDA_HPP_INCLUDED #include <boost/mpl/lambda.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/preprocessor/facilities/intercept.hpp> namespace boost { namespace fusion { namespace result_of { template<typename PlaceholderExpression> struct lambda { template < BOOST_PP_ENUM_BINARY_PARAMS(BOOST_MPL_LIMIT_METAFUNCTION_ARITY, typename T, = mpl::na BOOST_PP_INTERCEPT) > struct result : mpl::lambda<PlaceholderExpression>::type::template apply< BOOST_PP_ENUM_PARAMS(BOOST_MPL_LIMIT_METAFUNCTION_ARITY, T) > { }; }; }}} #endif

Tobias Schwinger wrote:
Here's an implementation.
I changed the name from 'result' to 'lambda' (because nested classes shouldn't have the same name as the enclosing ones).
FILES: ======
o lambda.hpp MPL-lambda adapter for result computation o lambda_test.cpp test/example for MPL-lambda adapter
TESTED WITH: ============
o GCC 3.4.2 o MSVC 8.0 o MSVC 7.1
It works really well -- the technique also reduces ambiguity problems caused by ADL with mutliple namespaces!
Hope you like it as much as I do...
Tobias, this looks really delicious! I'd love to see more of it! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Tobias, this looks really delicious! I'd love to see more of it!
OK. I just uploaded my modded Fusion files to the vault: http://tinyurl.com/ms3kd (archive of modified files) (Sorry, didn't have a CVS version, so it's diff-it-yourself -- where does it live, anyway?) The archive includes: - the lambda adaptor (it's called lambda_result now and supports partial binding to template parameters) - several tests for the lambda adaptor (code reads even better now) - the generic generators (make_*) as suggested during review - the minor fixes I recently sent to the tracker - a naive bind implementation that shows both the lambda stuff and the generic generators in action I noticed several bugs in fusion::unpack_args (maybe one of them is rooted elsewhere) and wrote a small program that shows the problems: http://tinyurl.com/kzlm5 (.cpp file) Enjoy, Tobias

Tobias Schwinger wrote:
Joel de Guzman wrote:
Tobias, this looks really delicious! I'd love to see more of it!
OK. I just uploaded my modded Fusion files to the vault:
http://tinyurl.com/ms3kd (archive of modified files)
Way cool!
(Sorry, didn't have a CVS version, so it's diff-it-yourself -- where does it live, anyway?)
You do have write access to the Spirit CVS right? If not, email me and I'll give you one. It is in the Spirit CVS at branch FUSION_V2. Please place your code in a new branch. We can merge later when things settle down a bit.
The archive includes: - the lambda adaptor (it's called lambda_result now and supports partial binding to template parameters) - several tests for the lambda adaptor (code reads even better now) - the generic generators (make_*) as suggested during review - the minor fixes I recently sent to the tracker - a naive bind implementation that shows both the lambda stuff and the generic generators in action
I noticed several bugs in fusion::unpack_args (maybe one of them is rooted elsewhere) and wrote a small program that shows the problems:
http://tinyurl.com/kzlm5 (.cpp file)
Please patch the FUSION_V2 branch if you will. The small test program can perhaps be merged with the unpack_args test. Thanks! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Tobias Schwinger wrote:
http://tinyurl.com/ms3kd (archive of modified files)
Took it offline -- still too much severe errors in there... The code that goes into the CVS will be clean. Regards, Tobias

Tobias Schwinger wrote:
I noticed several bugs in fusion::unpack_args (maybe one of them is rooted elsewhere) and wrote a small program that shows the problems:
http://tinyurl.com/kzlm5 (.cpp file)
Joao just fixed the CVS version. The file has been removed from the vault.

Tobias Schwinger wrote:
Tobias Schwinger wrote:
I noticed several bugs in fusion::unpack_args (maybe one of them is rooted elsewhere) and wrote a small program that shows the problems:
http://tinyurl.com/kzlm5 (.cpp file)
Joao just fixed the CVS version. The file has been removed from the vault.
Cool! Thanks Tobias and Joao. Cheers Dan

Tobias Schwinger wrote:
Tobias Schwinger wrote:
I noticed several bugs in fusion::unpack_args (maybe one of them is rooted elsewhere) and wrote a small program that shows the problems:
http://tinyurl.com/kzlm5 (.cpp file)
Joao just fixed the CVS version. The file has been removed from the vault.
For the record... Tobias test case exposed some serious shortcomings in the implementation of unpack_args, which should now be fixed in CVS. They were: 1 - support for function pointers was completely broken. Specifically, I learned that result_of doesn't handle cv-qualified function pointers. 2 - Random Access Sequences were required when Forward Sequences would have been sufficient. Here I failed to grasp the Fusion Concepts while porting unpack_args from Fusion v1. 3 - Function references weren't handled at all. I also took the opportunity to rewrite and expand the test case, hopefully making it a bit more readable in the process... I'll take comments on that too ;-) Thanks for the report and the test case! João

João Abecasis <jpabecasis@gmail.com> writes:
Tobias Schwinger wrote:
Tobias Schwinger wrote:
I noticed several bugs in fusion::unpack_args (maybe one of them is
rooted elsewhere) and wrote a small program that shows the problems:
http://tinyurl.com/kzlm5 (.cpp file)
Joao just fixed the CVS version. The file has been removed from the vault.
For the record... Tobias test case exposed some serious shortcomings in
the implementation of unpack_args, which should now be fixed in CVS.
They were:
1 - support for function pointers was completely broken. Specifically, I
learned that result_of doesn't handle cv-qualified function pointers.
Shouldn't we fix result_of?
2 - Random Access Sequences were required when Forward Sequences would
have been sufficient. Here I failed to grasp the Fusion Concepts while
porting unpack_args from Fusion v1.
3 - Function references weren't handled at all.
A result_of problem, or something else? -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
João Abecasis <jpabecasis@gmail.com> writes:
1 - support for function pointers was completely broken. Specifically, I learned that result_of doesn't handle cv-qualified function pointers.
Shouldn't we fix result_of?
I think so. I posted about the issues I found with result_of and is_pointer separately.
2 - Random Access Sequences were required when Forward Sequences would have been sufficient. Here I failed to grasp the Fusion Concepts while porting unpack_args from Fusion v1.
3 - Function references weren't handled at all.
A result_of problem, or something else?
In this case, something else, in my naive implementation I thought everything would be solved with a simple: typedef result_of<F(A0, ..., AN)>::type result_type; But it turns out that if F is a function the compiler will complain that we're trying to write a function returning a function. In the end, what I did, specifically for this case, was to add a pointer to the function type. Here I also found an issue with cv-qualified functions (if they do exist...) and is_function. This one seems to be gcc-4.x specific. Best regards, João

João Abecasis wrote:
1 - support for function pointers was completely broken. Specifically, I learned that result_of doesn't handle cv-qualified function pointers.
<snip>
3 - Function references weren't handled at all.
Taking the function argument by value (just like the STL) could help. Regards, Tobias

Tobias Schwinger wrote:
João Abecasis wrote:
1 - support for function pointers was completely broken. Specifically, I learned that result_of doesn't handle cv-qualified function pointers.
<snip>
3 - Function references weren't handled at all.
Taking the function argument by value (just like the STL) could help. ...which might be why result_of doesn't address the cases you describe.
We can still optimize the forwarding from unpack_args to unpack_args_impl and the client can optimize the forwarding to unpack_args by explicitly specifying the first template argument (see attached code). Regards, Tobias #include <boost/mpl/eval_if.hpp> #include <boost/mpl/identity.hpp> #include <boost/type_traits/is_class.hpp> #include <boost/type_traits/add_reference.hpp> namespace boost { namespace somewhere { namespace utility { template<typename F> struct forward_functor : mpl::eval_if< is_class<F>, add_reference<F>, mpl::identity<F> > { }; } namespace detail { template <typename F> struct func_acceptor_impl { static void accept_func(F f); // take f by whatever F is }; } template <typename F> void accept_func(F f) // take f by value { detail::func_acceptor_impl< typename utility::forward_functor<F>::type >::accept_func(f); } //---- template<typename F> void performance_critical_algorithm(F f) // client that uses the forward_functor metafunction and a non-deduced // template argument to reduce copying { for (; /* often */ ;) accept_func< typename utility::forward_functor<F>::type > (f); } struct a_class { }; void test() // instantiates templates { accept_func( static_cast< void(&)() > ( test) ); accept_func( test ); accept_func( static_cast< void(*)() > (& test) ); accept_func( & test ); accept_func( a_class() ); performance_critical_algorithm( static_cast< void(&)() > ( test) ); performance_critical_algorithm( test ); performance_critical_algorithm( static_cast< void(*)() > (& test) ); performance_critical_algorithm( & test ); performance_critical_algorithm( a_class() ); } } }

Tobias Schwinger wrote:
Tobias Schwinger wrote:
João Abecasis wrote:
1 - support for function pointers was completely broken. Specifically, I learned that result_of doesn't handle cv-qualified function pointers.
<snip>
3 - Function references weren't handled at all.
Taking the function argument by value (just like the STL) could help. ...which might be why result_of doesn't address the cases you describe.
Yes, I thought that would be the reason why this wasn't noticed before. Anyway, the code that's needed to allow for situations like these is minimal, so it was not too much trouble once I understood the issues: typedef mpl::eval_if< is_pointer<F>, remove_cv<F>, mpl::eval_if< is_function<remove_cv<F>::type>, add_pointer<remove_cv<F>::type>, mpl::identity<F> > >::type F_; typedef result_of<F_( args )>::type result_type;
We can still optimize the forwarding from unpack_args to unpack_args_impl and the client can optimize the forwarding to unpack_args by explicitly specifying the first template argument (see attached code).
The problem I had was that I needed a type for result_of (e.g., non-cv-qualified function pointer) and another type to pass around (e.g., function reference). By themselves, references work pretty well. Best regards, João

João Abecasis wrote:
The problem I had was that I needed a type for result_of (e.g., non-cv-qualified function pointer) and another type to pass around (e.g., function reference). By themselves, references work pretty well.
My point was that 'result_of' should work on 'F' as-is in the code from my previous post. Regards, Tobias
participants (5)
-
dan marsden
-
David Abrahams
-
Joel de Guzman
-
João Abecasis
-
Tobias Schwinger