
Christian Holmquist wrote:
Tobias, Thanks you for the reply on this matter.
Is your code available in the Boost Vault for download, and some example using it?
There used to be an early stage of both in the vault, but I took it offline once it was clear to me that it was still very much insufficient. I can only find the example code ITM and will attach it to this post.
There would be multiple variants of these class templates with different properties of the call operator:
- only accepting lvalues (like make_<seq>) - only accepting rvalues (like <seq>_tie)
Sorry, here's a typo - <seq>_tie binds lvalues and make_<seq> binds to rvalues, of course.
- only accepting predefined types (like <seq>'s ctor, this one would have another template parameter) - accepting any combination of lvalues and rvalues (exploding all 2^N possibilities - a brute force solution to the forwarding problem, until we have better ways to solve it)
I don't understand your reason for the lvalues/rvalues explotion. The distinct type is available in the fusion sequence, why overload completely unspecified types? (if that's what you do?).
<quote from your original post> template<class A0, class A1, ....> void operator()(const A0& a0, const A1& a1, ...) const { do_something_very_clever(fusion_sequence_type(a0, a1, ...)); } </quote from your original post> Here we don't know the template argument types, do we? It's the first case I mentioned (the most interesting cases are those where 'fusion_sequence_type' isn't known before operator() is instantiated). Although (almost) everything binds to "T const &" we can't know whether it was a temporary, so we can't safely store the refernce - it might start dangling. BTW: The result type is 'void'. If we want to factor this code out into some generic utility it's probably a wise choice to allow different results. The second case I mentioned is: template<class A0, class A1, ....> whatever operator()(A0& a0, A1& a1, ...) const; Now temporary arguments are not allowed at all (which can be very impractical of an interface) - a "pure tie". The fourth case lets us detect whether something is not a temporary, which can be a very valuable thing, especially if we want to defer function invocations. For an in-depth discussion of the issue see http://tinyurl.com/6enrw - The Forwarding Problem - Dimov, Hinnant, Abrahams
Given the sequence<int, int&, const int&> I would expect the overload to be (ignoring return type here) void operator()(int, int&, const int&).
In this case we are talking about the third case (the one where we know the types).
I assume I've oversimplified the issue, so what aspect am I missing here?
Never mind - I did so two times. I'm talking about how things should be done and not about I did them, after all. 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). //------------------------------------------------------------------------------ // // A simple bind implementation (compiles with msvc >= 7.1) // #include <typeinfo> #include <iostream> #include <boost/fusion/sequence/container/vector/vector.hpp> #include <boost/fusion/sequence/intrinsic/front.hpp> #include <boost/fusion/sequence/intrinsic/value_at.hpp> #include <boost/fusion/sequence/intrinsic/at.hpp> #include <boost/fusion/sequence/utility/unpack_args.hpp> #include <boost/fusion/algorithm/transformation/transform.hpp> #include <boost/fusion/algorithm/transformation/pop_front.hpp> // "case 1" from the post NOTE: NOT PART OF FUSION #include <boost/fusion/sequence/generation/vector_generator.hpp> // this header defines an experimental component that allows to specify the // result of a Fusion function object with an MPL lambda expression // NOTE: NOT PART OF FUSION #include <boost/fusion/support/lambda_result.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/bool.hpp> #include <boost/type_traits/add_const.hpp> #include <boost/type_traits/add_reference.hpp> // needed to workaround unpack_args bug #include <boost/fusion/sequence/conversion/as_vector.hpp> // note: another bug in unpack_args keeps this binder from working with // non-class functors. namespace impl { // note: one character identifiers keep qualified names short namespace r = boost::fusion; // r for runtime code namespace m = boost::fusion::result_of; // m for metafunctions namespace mpl = boost::mpl; using namespace mpl::placeholders; // use runtime code by default, using namespace r; // metafunctions unlikely to clash can go here using boost::add_const; using boost::add_reference; // placeholder template template<int I> struct placeholder : mpl::int_<I> { }; // is T the type of a placeholder? template<typename T> struct is_placeholder : mpl::false_ { }; template<int I> struct is_placeholder< placeholder<I> > : mpl::true_ { }; // runtime code for the transform operation template<typename Args> class transform_op : public lambda_result < mpl::if_< is_placeholder<_2>, m::at< add_const<_1>, _2> , add_reference< add_const<_2> > > > ::template closure<Args> { Args const & ref_args; public: explicit transform_op(Args const & args) : ref_args(args) { } // return bound argument template<typename BindingArg> inline BindingArg const & operator()(BindingArg const & a) const { return a; } // substitute placeholders with elements from the arguments tuple template<int Index> inline typename m::at_c<Args const, Index>::type operator()(placeholder<Index> const &) const { return at_c<Index>(this->ref_args); } }; // bound_function's operator() contains the argument transformation and // invokes the function template<class Binding> class bound_function : public lambda_result < m::unpack_args< m::value_at< add_const<_1> , mpl::int_<0>::type> , m::as_vector< // <-- workaround for unpack_args bug m::transform< m::pop_front< add_const<_1> > , transform_op<_2> > > // <-- workaround for unpack_args bug > > ::template closure<Binding> { Binding tpl_binding; public: explicit bound_function(Binding const & binding) : tpl_binding(binding) { } template<typename Args> inline typename result<Args>::type operator()(Args const & args) const { return unpack_args( front(this->tpl_binding) , as_vector( // <-- workaround for unpack_args bug transform( pop_front(this->tpl_binding) , transform_op<Args>(args) ) ) // <-- workaround for unpack_args bug ); } typedef bound_function type; // we leave this out for the sake of simplicity -- a full bind is not // possible... typedef mpl::false_ accepts_nullary_sequence; }; // vector_generator is used to create a bound_function struct bind_op : lambda_result< vector_generator< bound_function<_> > > { template<typename Binding> inline typename result<Binding>::type operator()(Binding const & binding) const { return typename result<Binding>::type(bound_function<Binding>(binding)); } }; typedef vector_generator<bind_op, mpl::false_> binder; } // placeholder globals impl::placeholder<0> const _1_ = impl::placeholder<0>(); impl::placeholder<1> const _2_ = impl::placeholder<1>(); impl::placeholder<2> const _3_ = impl::placeholder<2>(); impl::placeholder<3> const _4_ = impl::placeholder<3>(); // the binder is a global variable with an overloaded call operator impl::binder const bind = impl::binder(); //// example code struct func { typedef int result_type; inline int operator()(char const * greeting, char const * name) const { std::cout << greeting << ' ' << name << '!' << std::endl; return 77; } }; int main() { func f; bind(f,"Hello",_1_)("Phoenix"); return 0; }