lambda.cpp

来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 204 行

CPP
204
字号
///////////////////////////////////////////////////////////////////////////////// lambda.hpp////  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)#include <sstream>#include <boost/version.hpp>#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>#if BOOST_VERSION < 103500# include <boost/spirit/fusion/sequence/at.hpp># include <boost/spirit/fusion/sequence/tuple.hpp>namespace boost { namespace fusion { namespace result_of { using namespace meta; }}}#else# include <boost/fusion/tuple.hpp>#endif#include <boost/typeof/typeof.hpp>#include <boost/typeof/std/sstream.hpp>#include <boost/typeof/std/ostream.hpp>#include <boost/typeof/std/iostream.hpp>#include <boost/type_traits/add_const.hpp>#include <boost/type_traits/add_reference.hpp>#include <boost/proto/core.hpp>#include <boost/proto/context.hpp>#include <boost/proto/transform.hpp>#include <boost/test/unit_test.hpp>#include <boost/test/floating_point_comparison.hpp>using namespace boost;// Forward declaration of the lambda expression wrappertemplate<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;};namespace grammar{    using namespace proto;    // The lambda grammar, with the transforms for calculating the max arity    struct Lambda      : or_<            when< terminal< placeholder<_> >,  mpl::next<placeholder_arity<_value> >() >          , when< terminal<_>,                 mpl::int_<0>() >          , when< nary_expr<_, vararg<_> >,    fold<_, mpl::int_<0>(), mpl::max<Lambda,_state>()> >        >    {};}// simple wrapper for calculating a lambda expression's arity.template<typename Expr>struct lambda_arity  : boost::result_of<grammar::Lambda(Expr, mpl::void_, mpl::void_)>{};// The lambda context is the same as the default context// with the addition of special handling for lambda placeholderstemplate<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    {        #if BOOST_VERSION < 103500        return fusion::at<I::value>(this->args_);        #else        return fusion::at<I>(this->args_);        #endif    }    Tuple args_;};// The lambda<> expression wrapper makes expressions polymorphic// function objectstemplate<typename T>struct lambda{    BOOST_PROTO_BASIC_EXTENDS(T, lambda<T>, lambda_domain)    BOOST_PROTO_EXTENDS_ASSIGN()    BOOST_PROTO_EXTENDS_SUBSCRIPT()    // Careful not to evaluate the return type of the nullary function    // unless we have a nullary lambda!    typedef typename mpl::eval_if<        typename lambda_arity<T>::type      , mpl::identity<void>      , proto::result_of::eval<T const, lambda_context<fusion::tuple<> > >    >::type nullary_type;    // Define our operator () that evaluates the lambda expression.    nullary_type operator ()() const    {        fusion::tuple<> args;        lambda_context<fusion::tuple<> > ctx(args);        return proto::eval(*this, ctx);    }    template<typename A0>    typename proto::result_of::eval<T const, lambda_context<fusion::tuple<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 proto::result_of::eval<T const, lambda_context<fusion::tuple<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 placeholderslambda<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;}void test_lambda(){    BOOST_CHECK_EQUAL(11, ( (_1 + 2) / 4 )(42));    BOOST_CHECK_EQUAL(-11, ( (-(_1 + 2)) / 4 )(42));    BOOST_CHECK_CLOSE(2.58, ( (4 - _2) * 3 )(42, 3.14), 0.1);    // check non-const ref terminals    std::stringstream sout;    (sout << _1 << " -- " << _2)(42, "Life, the Universe and Everything!");    BOOST_CHECK_EQUAL("42 -- Life, the Universe and Everything!", sout.str());    // check nullary lambdas    BOOST_CHECK_EQUAL(3, (val(1) + val(2))());    // check array indexing for kicks    int integers[5] = {0};    (var(integers)[2] = 2)();    (var(integers)[_1] = _1)(3);    BOOST_CHECK_EQUAL(2, integers[2]);    BOOST_CHECK_EQUAL(3, integers[3]);}using namespace unit_test;///////////////////////////////////////////////////////////////////////////////// init_unit_test_suite//test_suite* init_unit_test_suite( int argc, char* argv[] ){    test_suite *test = BOOST_TEST_SUITE("test expression template domains");    test->add(BOOST_TEST_CASE(&test_lambda));    return test;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?