summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/proto/example/mini_lambda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/proto/example/mini_lambda.cpp')
-rw-r--r--src/boost/libs/proto/example/mini_lambda.cpp263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/boost/libs/proto/example/mini_lambda.cpp b/src/boost/libs/proto/example/mini_lambda.cpp
new file mode 100644
index 000000000..0f3d52c6d
--- /dev/null
+++ b/src/boost/libs/proto/example/mini_lambda.cpp
@@ -0,0 +1,263 @@
+//[ Lambda
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2008 Eric Niebler. 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)
+//
+// This example builds a simple but functional lambda library using Proto.
+
+#include <iostream>
+#include <algorithm>
+#include <boost/mpl/int.hpp>
+#include <boost/mpl/min_max.hpp>
+#include <boost/mpl/eval_if.hpp>
+#include <boost/mpl/identity.hpp>
+#include <boost/mpl/next_prior.hpp>
+#include <boost/fusion/tuple.hpp>
+#include <boost/typeof/typeof.hpp>
+#include <boost/typeof/std/ostream.hpp>
+#include <boost/typeof/std/iostream.hpp>
+#include <boost/proto/core.hpp>
+#include <boost/proto/context.hpp>
+#include <boost/proto/transform.hpp>
+namespace mpl = boost::mpl;
+namespace proto = boost::proto;
+namespace fusion = boost::fusion;
+using proto::_;
+
+// Forward declaration of the lambda expression wrapper
+template<typename T>
+struct lambda;
+
+struct lambda_domain
+ : proto::domain<proto::pod_generator<lambda> >
+{};
+
+template<typename I>
+struct placeholder
+{
+ typedef I arity;
+};
+
+template<typename T>
+struct placeholder_arity
+{
+ typedef typename T::arity type;
+};
+
+// The lambda grammar, with the transforms for calculating the max arity
+struct lambda_arity
+ : proto::or_<
+ proto::when<
+ proto::terminal< placeholder<_> >
+ , mpl::next<placeholder_arity<proto::_value> >()
+ >
+ , proto::when< proto::terminal<_>
+ , mpl::int_<0>()
+ >
+ , proto::when<
+ proto::nary_expr<_, proto::vararg<_> >
+ , proto::fold<_, mpl::int_<0>(), mpl::max<lambda_arity, proto::_state>()>
+ >
+ >
+{};
+
+// The lambda context is the same as the default context
+// with the addition of special handling for lambda placeholders
+template<typename Tuple>
+struct lambda_context
+ : proto::callable_context<lambda_context<Tuple> const>
+{
+ lambda_context(Tuple const &args)
+ : args_(args)
+ {}
+
+ template<typename Sig>
+ struct result;
+
+ template<typename This, typename I>
+ struct result<This(proto::tag::terminal, placeholder<I> const &)>
+ : fusion::result_of::at<Tuple, I>
+ {};
+
+ template<typename I>
+ typename fusion::result_of::at<Tuple, I>::type
+ operator ()(proto::tag::terminal, placeholder<I> const &) const
+ {
+ return fusion::at<I>(this->args_);
+ }
+
+ Tuple args_;
+};
+
+// The lambda<> expression wrapper makes expressions polymorphic
+// function objects
+template<typename T>
+struct lambda
+{
+ BOOST_PROTO_BASIC_EXTENDS(T, lambda<T>, lambda_domain)
+ BOOST_PROTO_EXTENDS_ASSIGN()
+ BOOST_PROTO_EXTENDS_SUBSCRIPT()
+
+ // Calculate the arity of this lambda expression
+ static int const arity = boost::result_of<lambda_arity(T)>::type::value;
+
+ template<typename Sig>
+ struct result;
+
+ // Define nested result<> specializations to calculate the return
+ // type of this lambda expression. But be careful not to evaluate
+ // the return type of the nullary function unless we have a nullary
+ // lambda!
+ template<typename This>
+ struct result<This()>
+ : mpl::eval_if_c<
+ 0 == arity
+ , proto::result_of::eval<T const, lambda_context<fusion::tuple<> > >
+ , mpl::identity<void>
+ >
+ {};
+
+ template<typename This, typename A0>
+ struct result<This(A0)>
+ : proto::result_of::eval<T const, lambda_context<fusion::tuple<A0> > >
+ {};
+
+ template<typename This, typename A0, typename A1>
+ struct result<This(A0, A1)>
+ : proto::result_of::eval<T const, lambda_context<fusion::tuple<A0, A1> > >
+ {};
+
+ // Define our operator () that evaluates the lambda expression.
+ typename result<lambda()>::type
+ operator ()() const
+ {
+ fusion::tuple<> args;
+ lambda_context<fusion::tuple<> > ctx(args);
+ return proto::eval(*this, ctx);
+ }
+
+ template<typename A0>
+ typename result<lambda(A0 const &)>::type
+ operator ()(A0 const &a0) const
+ {
+ fusion::tuple<A0 const &> args(a0);
+ lambda_context<fusion::tuple<A0 const &> > ctx(args);
+ return proto::eval(*this, ctx);
+ }
+
+ template<typename A0, typename A1>
+ typename result<lambda(A0 const &, A1 const &)>::type
+ operator ()(A0 const &a0, A1 const &a1) const
+ {
+ fusion::tuple<A0 const &, A1 const &> args(a0, a1);
+ lambda_context<fusion::tuple<A0 const &, A1 const &> > ctx(args);
+ return proto::eval(*this, ctx);
+ }
+};
+
+// Define some lambda placeholders
+lambda<proto::terminal<placeholder<mpl::int_<0> > >::type> const _1 = {{}};
+lambda<proto::terminal<placeholder<mpl::int_<1> > >::type> const _2 = {{}};
+
+template<typename T>
+lambda<typename proto::terminal<T>::type> const val(T const &t)
+{
+ lambda<typename proto::terminal<T>::type> that = {{t}};
+ return that;
+}
+
+template<typename T>
+lambda<typename proto::terminal<T &>::type> const var(T &t)
+{
+ lambda<typename proto::terminal<T &>::type> that = {{t}};
+ return that;
+}
+
+template<typename T>
+struct construct_helper
+{
+ typedef T result_type; // for TR1 result_of
+
+ T operator()() const
+ { return T(); }
+
+ // Generate BOOST_PROTO_MAX_ARITY overloads of the
+ // following function call operator.
+#define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, A_const_ref_a, a)\
+ template<typename_A(N)> \
+ T operator()(A_const_ref_a(N)) const \
+ { return T(a(N)); }
+#define BOOST_PROTO_LOCAL_a BOOST_PROTO_a
+#include BOOST_PROTO_LOCAL_ITERATE()
+};
+
+// Generate BOOST_PROTO_MAX_ARITY-1 overloads of the
+// following construct() function template.
+#define M0(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \
+template<typename T, typename_A(N)> \
+typename proto::result_of::make_expr< \
+ proto::tag::function \
+ , lambda_domain \
+ , construct_helper<T> \
+ , A_const_ref(N) \
+>::type const \
+construct(A_const_ref_a(N)) \
+{ \
+ return proto::make_expr< \
+ proto::tag::function \
+ , lambda_domain \
+ >( \
+ construct_helper<T>() \
+ , ref_a(N) \
+ ); \
+}
+BOOST_PROTO_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_ARITY, M0)
+#undef M0
+
+struct S
+{
+ S() {}
+ S(int i, char c)
+ {
+ std::cout << "S(" << i << "," << c << ")\n";
+ }
+};
+
+int main()
+{
+ // Create some lambda objects and immediately
+ // invoke them by applying their operator():
+ int i = ( (_1 + 2) / 4 )(42);
+ std::cout << i << std::endl; // prints 11
+
+ int j = ( (-(_1 + 2)) / 4 )(42);
+ std::cout << j << std::endl; // prints -11
+
+ double d = ( (4 - _2) * 3 )(42, 3.14);
+ std::cout << d << std::endl; // prints 2.58
+
+ // check non-const ref terminals
+ (std::cout << _1 << " -- " << _2 << '\n')(42, "Life, the Universe and Everything!");
+ // prints "42 -- Life, the Universe and Everything!"
+
+ // "Nullary" lambdas work too
+ int k = (val(1) + val(2))();
+ std::cout << k << std::endl; // prints 3
+
+ // check array indexing for kicks
+ int integers[5] = {0};
+ (var(integers)[2] = 2)();
+ (var(integers)[_1] = _1)(3);
+ std::cout << integers[2] << std::endl; // prints 2
+ std::cout << integers[3] << std::endl; // prints 3
+
+ // Now use a lambda with an STL algorithm!
+ int rgi[4] = {1,2,3,4};
+ char rgc[4] = {'a','b','c','d'};
+ S rgs[4];
+
+ std::transform(rgi, rgi+4, rgc, rgs, construct<S>(_1, _2));
+ return 0;
+}
+//]