mirror of
https://github.com/boostorg/fusion.git
synced 2025-07-23 09:07:26 +02:00
Full merge from trunk at revision 41356 of entire boost-root tree.
[SVN r41369]
This commit is contained in:
@ -1,237 +0,0 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2006-2007 Tobias Schwinger
|
||||
|
||||
Use modification and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
Problem:
|
||||
|
||||
How to "do the Bind?"
|
||||
|
||||
This recipe shows how to implement a function binder, similar to
|
||||
Boost.Bind based on the Functional module of Fusion.
|
||||
|
||||
It works as follows:
|
||||
|
||||
'bind' is a global, stateless function object. It is implemented in
|
||||
fused form (fused_binder) and transformed into a variadic function
|
||||
object. When called, 'bind' returns another function object, which
|
||||
holds the arguments of the call to 'bind'. It is, again, implemented
|
||||
in fused form (fused_bound_function) and transformed into unfused
|
||||
form.
|
||||
==============================================================================*/
|
||||
|
||||
#include <boost/fusion/functional/invocation/invoke.hpp>
|
||||
#include <boost/fusion/functional/adapter/unfused_generic.hpp>
|
||||
#include <boost/fusion/functional/adapter/unfused_rvalue_args.hpp>
|
||||
#include <boost/fusion/support/deduce_sequence.hpp>
|
||||
|
||||
#include <boost/fusion/sequence/intrinsic/at.hpp>
|
||||
#include <boost/fusion/mpl.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/front.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/empty.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/transform.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/pop_front.hpp>
|
||||
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
|
||||
#include <boost/mpl/eval_if.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/mpl/int.hpp>
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace impl
|
||||
{
|
||||
namespace fusion = boost::fusion;
|
||||
namespace traits = boost::fusion::traits;
|
||||
namespace result_of = boost::fusion::result_of;
|
||||
namespace mpl = boost::mpl;
|
||||
using mpl::placeholders::_;
|
||||
|
||||
// Placeholders (we inherit from mpl::int_, so we can use placeholders
|
||||
// as indices for fusion::at, later)
|
||||
template <int I> struct placeholder : mpl::int_<I> { };
|
||||
|
||||
// A traits class to find out whether T is a placeholeder
|
||||
template <typename T> struct is_placeholder : mpl::false_ { };
|
||||
template <int I> struct is_placeholder< placeholder<I> > : mpl::true_ { };
|
||||
template <int I> struct is_placeholder< placeholder<I> & > : mpl::true_ { };
|
||||
template <int I> struct is_placeholder< placeholder<I> const > : mpl::true_ { };
|
||||
template <int I> struct is_placeholder< placeholder<I> const & > : mpl::true_ { };
|
||||
|
||||
// This class template provides a Polymorphic Function Object to be used
|
||||
// with fusion::transform. It is applied to the sequence of arguments that
|
||||
// describes the binding and holds a reference to the sequence of arguments
|
||||
// from the final call.
|
||||
template<class FinalArgs> struct argument_transform
|
||||
{
|
||||
FinalArgs const & ref_final_args;
|
||||
public:
|
||||
|
||||
explicit argument_transform(FinalArgs const & final_args)
|
||||
: ref_final_args(final_args)
|
||||
{ }
|
||||
|
||||
// A placeholder? Replace it with an argument from the final call...
|
||||
template <int Index>
|
||||
inline typename result_of::at_c<FinalArgs const, Index>::type
|
||||
operator()(placeholder<Index> const &) const
|
||||
{
|
||||
return fusion::at_c<Index>(this->ref_final_args);
|
||||
}
|
||||
// ...just return the bound argument, otherwise.
|
||||
template <typename T> inline T & operator()(T & bound) const
|
||||
{
|
||||
return bound;
|
||||
}
|
||||
|
||||
template <typename Signature>
|
||||
struct result;
|
||||
|
||||
template <class Self, typename T>
|
||||
struct result< Self (T) >
|
||||
: mpl::eval_if< is_placeholder<T>,
|
||||
result_of::at<FinalArgs,typename boost::remove_reference<T>::type>,
|
||||
mpl::identity<T>
|
||||
>
|
||||
{ };
|
||||
};
|
||||
|
||||
// Fused implementation of the bound function, the function object
|
||||
// returned by bind
|
||||
template <class BindArgs> class fused_bound_function
|
||||
{
|
||||
typedef typename traits::deduce_sequence<BindArgs>::type bound_args;
|
||||
|
||||
bound_args fsq_bind_args;
|
||||
public:
|
||||
|
||||
fused_bound_function(BindArgs const & bind_args)
|
||||
: fsq_bind_args(bind_args)
|
||||
{ }
|
||||
|
||||
template <typename Signature>
|
||||
struct result;
|
||||
|
||||
template <class FinalArgs>
|
||||
struct result_impl
|
||||
: result_of::invoke< typename result_of::front<bound_args>::type,
|
||||
typename result_of::transform<
|
||||
typename result_of::pop_front<bound_args>::type,
|
||||
argument_transform<FinalArgs> const
|
||||
>::type
|
||||
>
|
||||
{ };
|
||||
|
||||
template <class Self, class FinalArgs>
|
||||
struct result< Self (FinalArgs) >
|
||||
: result_impl< typename boost::remove_reference<FinalArgs>::type >
|
||||
{ };
|
||||
|
||||
template <class FinalArgs>
|
||||
inline typename result_impl<FinalArgs>::type
|
||||
operator()(FinalArgs const & final_args) const
|
||||
{
|
||||
return fusion::invoke( fusion::front(this->fsq_bind_args),
|
||||
fusion::transform( fusion::pop_front(this->fsq_bind_args),
|
||||
argument_transform<FinalArgs>(final_args) ) );
|
||||
}
|
||||
// Could add a non-const variant - omitted for readability
|
||||
|
||||
};
|
||||
|
||||
// Fused implementation of the 'bind' function
|
||||
struct fused_binder
|
||||
{
|
||||
template <class Signature>
|
||||
struct result;
|
||||
|
||||
template <class BindArgs>
|
||||
struct result_impl
|
||||
{
|
||||
// We have to transform the arguments so they are held by-value
|
||||
// in the returned function.
|
||||
typedef fusion::unfused_generic<
|
||||
fused_bound_function<BindArgs> > type;
|
||||
};
|
||||
|
||||
template <class Self, class BindArgs>
|
||||
struct result< Self (BindArgs) >
|
||||
: result_impl< typename boost::remove_reference<BindArgs>::type >
|
||||
{ };
|
||||
|
||||
template <class BindArgs>
|
||||
inline typename result_impl< BindArgs >::type
|
||||
operator()(BindArgs & bind_args) const
|
||||
{
|
||||
return typename result< void(BindArgs) >::type(bind_args);
|
||||
}
|
||||
};
|
||||
|
||||
// The binder's unfused type. We use unfused_rvalue_args to make that
|
||||
// thing more similar to Boost.Bind. Because of that we have to use
|
||||
// Boost.Ref (below in the sample code)
|
||||
typedef fusion::unfused_rvalue_args<fused_binder> 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 bind function is a global, too
|
||||
impl::binder const bind = impl::binder();
|
||||
|
||||
|
||||
// OK, let's try it out:
|
||||
|
||||
struct func
|
||||
{
|
||||
typedef int result_type;
|
||||
|
||||
inline int operator()() const
|
||||
{
|
||||
std::cout << "operator()" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename A>
|
||||
inline int operator()(A const & a) const
|
||||
{
|
||||
std::cout << "operator()(A const & a)" << std::endl;
|
||||
std::cout << " a = " << a << " A = " << typeid(A).name() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline int operator()(A const & a, B & b) const
|
||||
{
|
||||
std::cout << "operator()(A const & a, B & b)" << std::endl;
|
||||
std::cout << " a = " << a << " A = " << typeid(A).name() << std::endl;
|
||||
std::cout << " b = " << b << " B = " << typeid(B).name() << std::endl;
|
||||
return 2;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
func f;
|
||||
int value = 42;
|
||||
using boost::ref;
|
||||
|
||||
int errors = 0;
|
||||
errors += !( bind(f)() == 0);
|
||||
errors += !( bind(f,"Hi")() == 1);
|
||||
errors += !( bind(f,_1_)("there.") == 1);
|
||||
errors += !( bind(f,"The answer is",_1_)(value) == 2);
|
||||
errors += !( bind(f,_1_,ref(value))("Really?") == 2);
|
||||
errors += !( bind(f,_1_,_2_)("Dunno. If there is an answer, it's",value) == 2);
|
||||
|
||||
return !! errors;
|
||||
}
|
||||
|
@ -1,105 +0,0 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 2006 Joel de Guzman
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Problem:
|
||||
|
||||
So... you have an input sequence I and a target vector R. You want to
|
||||
copy I into R. But, I may have less elements than the result vector R.
|
||||
For those elements not in R, you want them to be default constructed.
|
||||
|
||||
Here's a case:
|
||||
|
||||
I: list<double, std::string>
|
||||
R: vector<double, std::string, int, short>
|
||||
|
||||
You want the elements at the right of I not in R (i.e. int, short)
|
||||
default constructed. Those at the left, found in both I and R, you want
|
||||
to simply copy from I.
|
||||
|
||||
Of course you want to be able to handle any type of I and R.
|
||||
|
||||
==============================================================================*/
|
||||
|
||||
// We'll use these containers as examples
|
||||
#include <boost/fusion/container/list.hpp>
|
||||
#include <boost/fusion/container/vector.hpp>
|
||||
|
||||
// For doing I/O
|
||||
#include <boost/fusion/sequence/io.hpp>
|
||||
|
||||
// We'll use join and advance for processing
|
||||
#include <boost/fusion/algorithm/transformation/join.hpp>
|
||||
#include <boost/fusion/iterator/advance.hpp>
|
||||
|
||||
// The fusion <--> MPL link header
|
||||
#include <boost/fusion/mpl.hpp>
|
||||
|
||||
// Same-o same-o
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace boost::fusion;
|
||||
using namespace boost;
|
||||
|
||||
// Let's specify our own tuple delimeters for nicer printing
|
||||
std::cout << tuple_open('[');
|
||||
std::cout << tuple_close(']');
|
||||
std::cout << tuple_delimiter(", ");
|
||||
|
||||
// Here's your input sequence
|
||||
typedef list<double, std::string> I;
|
||||
I i(123.456, "Hello");
|
||||
|
||||
// Here's your output sequence. For now, it is just a typedef
|
||||
typedef vector<double, std::string, int, short> R;
|
||||
|
||||
// Let's get the sizes of the sequences. Yeah, you already know that.
|
||||
// But with templates, you are simply given, say, R and I, corresponding
|
||||
// to the types of the sequences. You'll have to deal with it generically.
|
||||
static int const r_size = result_of::size<R>::value;
|
||||
static int const i_size = result_of::size<I>::value;
|
||||
|
||||
// Make sure that I has no more elements than R
|
||||
// Be nice and catch obvious errors earlier rather than later.
|
||||
// Without this assert, the mistake will still be caught by Fusion,
|
||||
// but the error will point to somewhere really obscure.
|
||||
BOOST_STATIC_ASSERT(i_size <= r_size);
|
||||
|
||||
// Let's get the begin and end iterator types of the output sequence
|
||||
// There's no actual vector yet. We just want to know the types.
|
||||
typedef result_of::begin<R>::type r_begin;
|
||||
typedef result_of::end<R>::type r_end;
|
||||
|
||||
// Let's skip i_size elements from r_begin. Again, we just want to know the type.
|
||||
typedef result_of::advance_c<r_begin, i_size>::type r_advance;
|
||||
|
||||
// Now, make MPL iterators from r_advance and r_end. Ditto, just types.
|
||||
typedef mpl::fusion_iterator<r_advance> mpl_r_advance;
|
||||
typedef mpl::fusion_iterator<r_end> mpl_r_end;
|
||||
|
||||
// Make an mpl::iterator_range from the MPL iterators we just created
|
||||
// You guessed it! --just a type.
|
||||
typedef mpl::iterator_range<mpl_r_advance, mpl_r_end> tail;
|
||||
|
||||
// Use join to join the input sequence and our mpl::iterator_range
|
||||
// Our mpl::iterator_range is 'tail'. Here, we'll actually instantiate
|
||||
// 'tail'. Notice that this is a flyweight object, typically just 1 byte
|
||||
// in size -- it doesn't really hold any data, but is a fully conforming
|
||||
// sequence nonetheless. When asked to return its elements, 'tail' returns
|
||||
// each element default constructed. Breeds like a rabbit!
|
||||
|
||||
// Construct R from the joined sequences:
|
||||
R r(join(i, tail()));
|
||||
|
||||
// Then finally, print the result:
|
||||
std::cout << r << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user