early-access version 3088

This commit is contained in:
pineappleEA
2022-11-05 15:35:56 +01:00
parent 4e4fc25ce3
commit b601909c6d
35519 changed files with 5996896 additions and 860 deletions

View File

@@ -0,0 +1,87 @@
# (C) Copyright 2004: 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)
exe hello
:
hello.cpp
;
exe calc1
:
calc1.cpp
;
exe calc2
:
calc2.cpp
;
exe calc3
:
calc3.cpp
;
exe lazy_vector
:
lazy_vector.cpp
;
exe tarray
:
tarray.cpp
;
exe rgb
:
rgb.cpp
;
exe vec3
:
vec3.cpp
;
exe vector
:
vector.cpp
;
exe mixed
:
mixed.cpp
;
exe futures
:
futures.cpp
;
exe map_assign
:
map_assign.cpp
;
exe mini_lambda
:
mini_lambda.cpp
;
exe virtual_member
:
virtual_member.cpp
;
exe external_transforms
:
external_transforms.cpp
;
exe lambda
:
lambda.cpp
:
<include>.
<toolset>clang:<cxxflags>-Wno-unused-local-typedef
;

View File

@@ -0,0 +1,68 @@
//[ Calc1
// 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 is a simple example of how to build an arithmetic expression
// evaluator with placeholders.
#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
namespace proto = boost::proto;
using proto::_;
template<int I> struct placeholder {};
// Define some placeholders
proto::terminal< placeholder< 1 > >::type const _1 = {{}};
proto::terminal< placeholder< 2 > >::type const _2 = {{}};
// Define a calculator context, for evaluating arithmetic expressions
struct calculator_context
: proto::callable_context< calculator_context const >
{
// The values bound to the placeholders
double d[2];
// The result of evaluating arithmetic expressions
typedef double result_type;
explicit calculator_context(double d1 = 0., double d2 = 0.)
{
d[0] = d1;
d[1] = d2;
}
// Handle the evaluation of the placeholder terminals
template<int I>
double operator ()(proto::tag::terminal, placeholder<I>) const
{
return d[ I - 1 ];
}
};
template<typename Expr>
double evaluate( Expr const &expr, double d1 = 0., double d2 = 0. )
{
// Create a calculator context with d1 and d2 substituted for _1 and _2
calculator_context const ctx(d1, d2);
// Evaluate the calculator expression with the calculator_context
return proto::eval(expr, ctx);
}
int main()
{
// Displays "5"
std::cout << evaluate( _1 + 2.0, 3.0 ) << std::endl;
// Displays "6"
std::cout << evaluate( _1 * _2, 3.0, 2.0 ) << std::endl;
// Displays "0.5"
std::cout << evaluate( (_1 - _2) / _2, 3.0, 2.0 ) << std::endl;
return 0;
}
//]

View File

@@ -0,0 +1,103 @@
//[ Calc2
// 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 enhances the simple arithmetic expression evaluator
// in calc1.cpp by using proto::extends to make arithmetic
// expressions immediately evaluable with operator (), a-la a
// function object
#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
namespace proto = boost::proto;
using proto::_;
template<typename Expr>
struct calculator_expression;
// Tell proto how to generate expressions in the calculator_domain
struct calculator_domain
: proto::domain<proto::generator<calculator_expression> >
{};
// Will be used to define the placeholders _1 and _2
template<int I> struct placeholder {};
// Define a calculator context, for evaluating arithmetic expressions
// (This is as before, in calc1.cpp)
struct calculator_context
: proto::callable_context< calculator_context const >
{
// The values bound to the placeholders
double d[2];
// The result of evaluating arithmetic expressions
typedef double result_type;
explicit calculator_context(double d1 = 0., double d2 = 0.)
{
d[0] = d1;
d[1] = d2;
}
// Handle the evaluation of the placeholder terminals
template<int I>
double operator ()(proto::tag::terminal, placeholder<I>) const
{
return d[ I - 1 ];
}
};
// Wrap all calculator expressions in this type, which defines
// operator () to evaluate the expression.
template<typename Expr>
struct calculator_expression
: proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
explicit calculator_expression(Expr const &expr = Expr())
: calculator_expression::proto_extends(expr)
{}
BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>)
// Override operator () to evaluate the expression
double operator ()() const
{
calculator_context const ctx;
return proto::eval(*this, ctx);
}
double operator ()(double d1) const
{
calculator_context const ctx(d1);
return proto::eval(*this, ctx);
}
double operator ()(double d1, double d2) const
{
calculator_context const ctx(d1, d2);
return proto::eval(*this, ctx);
}
};
// Define some placeholders (notice they're wrapped in calculator_expression<>)
calculator_expression<proto::terminal< placeholder< 1 > >::type> const _1;
calculator_expression<proto::terminal< placeholder< 2 > >::type> const _2;
// Now, our arithmetic expressions are immediately executable function objects:
int main()
{
// Displays "5"
std::cout << (_1 + 2.0)( 3.0 ) << std::endl;
// Displays "6"
std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl;
// Displays "0.5"
std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl;
return 0;
}
//]

View File

@@ -0,0 +1,154 @@
//[ Calc3
// 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 enhances the arithmetic expression evaluator
// in calc2.cpp by using a proto transform to calculate the
// number of arguments an expression requires and using a
// compile-time assert to guarantee that the right number of
// arguments are actually specified.
#include <iostream>
#include <boost/mpl/int.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/min_max.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/proto/transform.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
// Will be used to define the placeholders _1 and _2
template<typename I> struct placeholder : I {};
// This grammar basically says that a calculator expression is one of:
// - A placeholder terminal
// - Some other terminal
// - Some non-terminal whose children are calculator expressions
// In addition, it has transforms that say how to calculate the
// expression arity for each of the three cases.
struct CalculatorGrammar
: proto::or_<
// placeholders have a non-zero arity ...
proto::when< proto::terminal< placeholder<_> >, proto::_value >
// Any other terminals have arity 0 ...
, proto::when< proto::terminal<_>, mpl::int_<0>() >
// For any non-terminals, find the arity of the children and
// take the maximum. This is recursive.
, proto::when< proto::nary_expr<_, proto::vararg<_> >
, proto::fold<_, mpl::int_<0>(), mpl::max<CalculatorGrammar, proto::_state>() > >
>
{};
// Simple wrapper for calculating a calculator expression's arity.
// It specifies mpl::int_<0> as the initial state. The data, which
// is not used, is mpl::void_.
template<typename Expr>
struct calculator_arity
: boost::result_of<CalculatorGrammar(Expr)>
{};
template<typename Expr>
struct calculator_expression;
// Tell proto how to generate expressions in the calculator_domain
struct calculator_domain
: proto::domain<proto::generator<calculator_expression> >
{};
// Define a calculator context, for evaluating arithmetic expressions
// (This is as before, in calc1.cpp and calc2.cpp)
struct calculator_context
: proto::callable_context< calculator_context const >
{
// The values bound to the placeholders
double d[2];
// The result of evaluating arithmetic expressions
typedef double result_type;
explicit calculator_context(double d1 = 0., double d2 = 0.)
{
d[0] = d1;
d[1] = d2;
}
// Handle the evaluation of the placeholder terminals
template<typename I>
double operator ()(proto::tag::terminal, placeholder<I>) const
{
return d[ I() - 1 ];
}
};
// Wrap all calculator expressions in this type, which defines
// operator () to evaluate the expression.
template<typename Expr>
struct calculator_expression
: proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
typedef
proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
base_type;
explicit calculator_expression(Expr const &expr = Expr())
: base_type(expr)
{}
BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>)
// Override operator () to evaluate the expression
double operator ()() const
{
// Assert that the expression has arity 0
BOOST_MPL_ASSERT_RELATION(0, ==, calculator_arity<Expr>::type::value);
calculator_context const ctx;
return proto::eval(*this, ctx);
}
double operator ()(double d1) const
{
// Assert that the expression has arity 1
BOOST_MPL_ASSERT_RELATION(1, ==, calculator_arity<Expr>::type::value);
calculator_context const ctx(d1);
return proto::eval(*this, ctx);
}
double operator ()(double d1, double d2) const
{
// Assert that the expression has arity 2
BOOST_MPL_ASSERT_RELATION(2, ==, calculator_arity<Expr>::type::value);
calculator_context const ctx(d1, d2);
return proto::eval(*this, ctx);
}
};
// Define some placeholders (notice they're wrapped in calculator_expression<>)
calculator_expression<proto::terminal< placeholder< mpl::int_<1> > >::type> const _1;
calculator_expression<proto::terminal< placeholder< mpl::int_<2> > >::type> const _2;
// Now, our arithmetic expressions are immediately executable function objects:
int main()
{
// Displays "5"
std::cout << (_1 + 2.0)( 3.0 ) << std::endl;
// Displays "6"
std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl;
// Displays "0.5"
std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl;
// This won't compile because the arity of the
// expression doesn't match the number of arguments
// ( (_1 - _2) / _2 )( 3.0 );
return 0;
}
//]

View File

@@ -0,0 +1,128 @@
//[ CheckedCalc
// Copyright 2011 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 is an example of how to specify a transform externally so
// that a single grammar can be used to drive multiple differnt
// calculations. In particular, it defines a calculator grammar
// that computes the result of an expression with either checked
// or non-checked division.
#include <iostream>
#include <boost/assert.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/min_max.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/container/generation/make_vector.hpp>
#include <boost/proto/proto.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace fusion = boost::fusion;
// The argument placeholder type
template<typename I> struct placeholder : I {};
// Give each rule in the grammar a "name". This is so that we
// can easily dispatch on it later.
struct calc_grammar;
struct divides_rule : proto::divides<calc_grammar, calc_grammar> {};
// Use external transforms in calc_gramar
struct calc_grammar
: proto::or_<
proto::when<
proto::terminal<placeholder<proto::_> >
, proto::functional::at(proto::_state, proto::_value)
>
, proto::when<
proto::terminal<proto::convertible_to<double> >
, proto::_value
>
, proto::when<
proto::plus<calc_grammar, calc_grammar>
, proto::_default<calc_grammar>
>
, proto::when<
proto::minus<calc_grammar, calc_grammar>
, proto::_default<calc_grammar>
>
, proto::when<
proto::multiplies<calc_grammar, calc_grammar>
, proto::_default<calc_grammar>
>
// Note that we don't specify how division nodes are
// handled here. Proto::external_transform is a placeholder
// for an actual transform.
, proto::when<
divides_rule
, proto::external_transform
>
>
{};
template<typename E> struct calc_expr;
struct calc_domain : proto::domain<proto::generator<calc_expr> > {};
template<typename E>
struct calc_expr
: proto::extends<E, calc_expr<E>, calc_domain>
{
calc_expr(E const &e = E()) : calc_expr::proto_extends(e) {}
};
calc_expr<proto::terminal<placeholder<mpl::int_<0> > >::type> _1;
calc_expr<proto::terminal<placeholder<mpl::int_<1> > >::type> _2;
// Use proto::external_transforms to map from named grammar rules to
// transforms.
struct non_checked_division
: proto::external_transforms<
proto::when< divides_rule, proto::_default<calc_grammar> >
>
{};
struct division_by_zero : std::exception {};
struct do_checked_divide
: proto::callable
{
typedef int result_type;
int operator()(int left, int right) const
{
if (right == 0) throw division_by_zero();
return left / right;
}
};
// Use proto::external_transforms again, this time to map the divides_rule
// to a transforms that performs checked division.
struct checked_division
: proto::external_transforms<
proto::when<
divides_rule
, do_checked_divide(calc_grammar(proto::_left), calc_grammar(proto::_right))
>
>
{};
int main()
{
non_checked_division non_checked;
int result2 = calc_grammar()(_1 / _2, fusion::make_vector(6, 2), non_checked);
BOOST_ASSERT(result2 == 3);
try
{
checked_division checked;
// This should throw
int result3 = calc_grammar()(_1 / _2, fusion::make_vector(6, 0), checked);
BOOST_ASSERT(false); // shouldn't get here!
}
catch(division_by_zero)
{
std::cout << "caught division by zero!\n";
}
}
//]

View File

@@ -0,0 +1,134 @@
//[ FutureGroup
// 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 is an example of using Proto transforms to implement
// Howard Hinnant's future group proposal.
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/joint_view.hpp>
#include <boost/fusion/include/single_view.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace fusion = boost::fusion;
using proto::_;
template<class L,class R>
struct pick_left
{
BOOST_MPL_ASSERT((boost::is_same<L, R>));
typedef L type;
};
// Work-arounds for Microsoft Visual C++ 7.1
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#define FutureGroup(x) proto::call<FutureGroup(x)>
#endif
// Define the grammar of future group expression, as well as a
// transform to turn them into a Fusion sequence of the correct
// type.
struct FutureGroup
: proto::or_<
// terminals become a single-element Fusion sequence
proto::when<
proto::terminal<_>
, fusion::single_view<proto::_value>(proto::_value)
>
// (a && b) becomes a concatenation of the sequence
// from 'a' and the one from 'b':
, proto::when<
proto::logical_and<FutureGroup, FutureGroup>
, fusion::joint_view<
boost::add_const<FutureGroup(proto::_left) >
, boost::add_const<FutureGroup(proto::_right) >
>(FutureGroup(proto::_left), FutureGroup(proto::_right))
>
// (a || b) becomes the sequence for 'a', so long
// as it is the same as the sequence for 'b'.
, proto::when<
proto::logical_or<FutureGroup, FutureGroup>
, pick_left<
FutureGroup(proto::_left)
, FutureGroup(proto::_right)
>(FutureGroup(proto::_left))
>
>
{};
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#undef FutureGroup
#endif
template<class E>
struct future_expr;
struct future_dom
: proto::domain<proto::generator<future_expr>, FutureGroup>
{};
// Expressions in the future group domain have a .get()
// member function that (ostensibly) blocks for the futures
// to complete and returns the results in an appropriate
// tuple.
template<class E>
struct future_expr
: proto::extends<E, future_expr<E>, future_dom>
{
explicit future_expr(E const &e)
: future_expr::proto_extends(e)
{}
typename fusion::result_of::as_vector<
typename boost::result_of<FutureGroup(E)>::type
>::type
get() const
{
return fusion::as_vector(FutureGroup()(*this));
}
};
// The future<> type has an even simpler .get()
// member function.
template<class T>
struct future
: future_expr<typename proto::terminal<T>::type>
{
future(T const &t = T())
: future::proto_derived_expr(future::proto_base_expr::make(t))
{}
T get() const
{
return proto::value(*this);
}
};
// TEST CASES
struct A {};
struct B {};
struct C {};
int main()
{
using fusion::vector;
future<A> a;
future<B> b;
future<C> c;
future<vector<A,B> > ab;
// Verify that various future groups have the
// correct return types.
A t0 = a.get();
vector<A, B, C> t1 = (a && b && c).get();
vector<A, C> t2 = ((a || a) && c).get();
vector<A, B, C> t3 = ((a && b || a && b) && c).get();
vector<vector<A, B>, C> t4 = ((ab || ab) && c).get();
return 0;
}
//]

View File

@@ -0,0 +1,28 @@
//[ HelloWorld
////////////////////////////////////////////////////////////////////
// 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 <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
// This #include is only needed for compilers that use typeof emulation:
#include <boost/typeof/std/ostream.hpp>
namespace proto = boost::proto;
proto::terminal< std::ostream & >::type cout_ = {std::cout};
template< typename Expr >
void evaluate( Expr const & expr )
{
proto::default_context ctx;
proto::eval(expr, ctx);
}
int main()
{
evaluate( cout_ << "hello" << ',' << " world" );
return 0;
}
//]

View File

@@ -0,0 +1,17 @@
//[ 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 "./lambda.hpp"
int main()
{
using namespace boost::lambda;
int i = (_1 + _1)(42);
std::cout << i << std::endl;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,142 @@
//[ LazyVector
///////////////////////////////////////////////////////////////////////////////
// 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 constructs a mini-library for linear algebra, using
// expression templates to eliminate the need for temporaries when
// adding vectors of numbers.
//
// This example uses a domain with a grammar to prune the set
// of overloaded operators. Only those operators that produce
// valid lazy vector expressions are allowed.
#include <vector>
#include <iostream>
#include <boost/mpl/int.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
template<typename Expr>
struct lazy_vector_expr;
// This grammar describes which lazy vector expressions
// are allowed; namely, vector terminals and addition
// and subtraction of lazy vector expressions.
struct LazyVectorGrammar
: proto::or_<
proto::terminal< std::vector<_> >
, proto::plus< LazyVectorGrammar, LazyVectorGrammar >
, proto::minus< LazyVectorGrammar, LazyVectorGrammar >
>
{};
// Tell proto that in the lazy_vector_domain, all
// expressions should be wrapped in laxy_vector_expr<>
// and must conform to the lazy vector grammar.
struct lazy_vector_domain
: proto::domain<proto::generator<lazy_vector_expr>, LazyVectorGrammar>
{};
// Here is an evaluation context that indexes into a lazy vector
// expression, and combines the result.
template<typename Size = std::size_t>
struct lazy_subscript_context
{
lazy_subscript_context(Size subscript)
: subscript_(subscript)
{}
// Use default_eval for all the operations ...
template<typename Expr, typename Tag = typename Expr::proto_tag>
struct eval
: proto::default_eval<Expr, lazy_subscript_context>
{};
// ... except for terminals, which we index with our subscript
template<typename Expr>
struct eval<Expr, proto::tag::terminal>
{
typedef typename proto::result_of::value<Expr>::type::value_type result_type;
result_type operator ()( Expr const & expr, lazy_subscript_context & ctx ) const
{
return proto::value( expr )[ ctx.subscript_ ];
}
};
Size subscript_;
};
// Here is the domain-specific expression wrapper, which overrides
// operator [] to evaluate the expression using the lazy_subscript_context.
template<typename Expr>
struct lazy_vector_expr
: proto::extends<Expr, lazy_vector_expr<Expr>, lazy_vector_domain>
{
lazy_vector_expr( Expr const & expr = Expr() )
: lazy_vector_expr::proto_extends( expr )
{}
// Use the lazy_subscript_context<> to implement subscripting
// of a lazy vector expression tree.
template< typename Size >
typename proto::result_of::eval< Expr, lazy_subscript_context<Size> >::type
operator []( Size subscript ) const
{
lazy_subscript_context<Size> ctx(subscript);
return proto::eval(*this, ctx);
}
};
// Here is our lazy_vector terminal, implemented in terms of lazy_vector_expr
template< typename T >
struct lazy_vector
: lazy_vector_expr< typename proto::terminal< std::vector<T> >::type >
{
typedef typename proto::terminal< std::vector<T> >::type expr_type;
lazy_vector( std::size_t size = 0, T const & value = T() )
: lazy_vector_expr<expr_type>( expr_type::make( std::vector<T>( size, value ) ) )
{}
// Here we define a += operator for lazy vector terminals that
// takes a lazy vector expression and indexes it. expr[i] here
// uses lazy_subscript_context<> under the covers.
template< typename Expr >
lazy_vector &operator += (Expr const & expr)
{
std::size_t size = proto::value(*this).size();
for(std::size_t i = 0; i < size; ++i)
{
proto::value(*this)[i] += expr[i];
}
return *this;
}
};
int main()
{
// lazy_vectors with 4 elements each.
lazy_vector< double > v1( 4, 1.0 ), v2( 4, 2.0 ), v3( 4, 3.0 );
// Add two vectors lazily and get the 2nd element.
double d1 = ( v2 + v3 )[ 2 ]; // Look ma, no temporaries!
std::cout << d1 << std::endl;
// Subtract two vectors and add the result to a third vector.
v1 += v2 - v3; // Still no temporaries!
std::cout << '{' << v1[0] << ',' << v1[1]
<< ',' << v1[2] << ',' << v1[3] << '}' << std::endl;
// This expression is disallowed because it does not conform
// to the LazyVectorGrammar
//(v2 + v3) += v1;
return 0;
}
//]

View File

@@ -0,0 +1,136 @@
//[ MapAssign
// 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 is a port of map_list_of() from the Boost.Assign library.
// It has the advantage of being more efficient at runtime by not
// building any temporary container that requires dynamic allocation.
#include <map>
#include <string>
#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>
#include <boost/type_traits/add_reference.hpp>
namespace proto = boost::proto;
using proto::_;
struct map_list_of_tag
{};
// A simple callable function object that inserts a
// (key,value) pair into a map.
struct insert
: proto::callable
{
template<typename Sig>
struct result;
template<typename This, typename Map, typename Key, typename Value>
struct result<This(Map, Key, Value)>
: boost::add_reference<Map>
{};
template<typename Map, typename Key, typename Value>
Map &operator()(Map &map, Key const &key, Value const &value) const
{
map.insert(typename Map::value_type(key, value));
return map;
}
};
// Work-arounds for Microsoft Visual C++ 7.1
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#define MapListOf(x) proto::call<MapListOf(x)>
#define _value(x) call<proto::_value(x)>
#endif
// The grammar for valid map-list expressions, and a
// transform that populates the map.
struct MapListOf
: proto::or_<
proto::when<
// map_list_of(a,b)
proto::function<
proto::terminal<map_list_of_tag>
, proto::terminal<_>
, proto::terminal<_>
>
, insert(
proto::_data
, proto::_value(proto::_child1)
, proto::_value(proto::_child2)
)
>
, proto::when<
// map_list_of(a,b)(c,d)...
proto::function<
MapListOf
, proto::terminal<_>
, proto::terminal<_>
>
, insert(
MapListOf(proto::_child0)
, proto::_value(proto::_child1)
, proto::_value(proto::_child2)
)
>
>
{};
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
#undef MapListOf
#undef _value
#endif
template<typename Expr>
struct map_list_of_expr;
struct map_list_of_dom
: proto::domain<proto::pod_generator<map_list_of_expr>, MapListOf>
{};
// An expression wrapper that provides a conversion to a
// map that uses the MapListOf
template<typename Expr>
struct map_list_of_expr
{
BOOST_PROTO_BASIC_EXTENDS(Expr, map_list_of_expr, map_list_of_dom)
BOOST_PROTO_EXTENDS_FUNCTION()
template<typename Key, typename Value, typename Cmp, typename Al>
operator std::map<Key, Value, Cmp, Al> () const
{
BOOST_MPL_ASSERT((proto::matches<Expr, MapListOf>));
std::map<Key, Value, Cmp, Al> map;
return MapListOf()(*this, 0, map);
}
};
map_list_of_expr<proto::terminal<map_list_of_tag>::type> const map_list_of = {{{}}};
int main()
{
// Initialize a map:
std::map<std::string, int> op =
map_list_of
("<", 1)
("<=",2)
(">", 3)
(">=",4)
("=", 5)
("<>",6)
;
std::cout << "\"<\" --> " << op["<"] << std::endl;
std::cout << "\"<=\" --> " << op["<="] << std::endl;
std::cout << "\">\" --> " << op[">"] << std::endl;
std::cout << "\">=\" --> " << op[">="] << std::endl;
std::cout << "\"=\" --> " << op["="] << std::endl;
std::cout << "\"<>\" --> " << op["<>"] << std::endl;
return 0;
}
//]

View File

@@ -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;
}
//]

View File

@@ -0,0 +1,375 @@
//[ Mixed
///////////////////////////////////////////////////////////////////////////////
// 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 is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy
// expressions using std::vector<> and std::list, non-proto types. It is a port
// of the Mixed example from PETE.
// (http://www.codesourcery.com/pooma/download.html).
#include <list>
#include <cmath>
#include <vector>
#include <complex>
#include <iostream>
#include <stdexcept>
#include <boost/proto/core.hpp>
#include <boost/proto/debug.hpp>
#include <boost/proto/context.hpp>
#include <boost/proto/transform.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/typeof/std/list.hpp>
#include <boost/typeof/std/vector.hpp>
#include <boost/typeof/std/complex.hpp>
#include <boost/type_traits/remove_reference.hpp>
namespace proto = boost::proto;
namespace mpl = boost::mpl;
using proto::_;
template<typename Expr>
struct MixedExpr;
template<typename Iter>
struct iterator_wrapper
{
typedef Iter iterator;
explicit iterator_wrapper(Iter iter)
: it(iter)
{}
mutable Iter it;
};
struct begin : proto::callable
{
template<class Sig>
struct result;
template<class This, class Cont>
struct result<This(Cont)>
: proto::result_of::as_expr<
iterator_wrapper<typename boost::remove_reference<Cont>::type::const_iterator>
>
{};
template<typename Cont>
typename result<begin(Cont const &)>::type
operator ()(Cont const &cont) const
{
iterator_wrapper<typename Cont::const_iterator> it(cont.begin());
return proto::as_expr(it);
}
};
// Here is a grammar that replaces vector and list terminals with their
// begin iterators
struct Begin
: proto::or_<
proto::when< proto::terminal< std::vector<_, _> >, begin(proto::_value) >
, proto::when< proto::terminal< std::list<_, _> >, begin(proto::_value) >
, proto::when< proto::terminal<_> >
, proto::when< proto::nary_expr<_, proto::vararg<Begin> > >
>
{};
// Here is an evaluation context that dereferences iterator
// terminals.
struct DereferenceCtx
{
// Unless this is an iterator terminal, use the
// default evaluation context
template<typename Expr, typename EnableIf = void>
struct eval
: proto::default_eval<Expr, DereferenceCtx const>
{};
// Dereference iterator terminals.
template<typename Expr>
struct eval<
Expr
, typename boost::enable_if<
proto::matches<Expr, proto::terminal<iterator_wrapper<_> > >
>::type
>
{
typedef typename proto::result_of::value<Expr>::type IteratorWrapper;
typedef typename IteratorWrapper::iterator iterator;
typedef typename std::iterator_traits<iterator>::reference result_type;
result_type operator ()(Expr &expr, DereferenceCtx const &) const
{
return *proto::value(expr).it;
}
};
};
// Here is an evaluation context that increments iterator
// terminals.
struct IncrementCtx
{
// Unless this is an iterator terminal, use the
// default evaluation context
template<typename Expr, typename EnableIf = void>
struct eval
: proto::null_eval<Expr, IncrementCtx const>
{};
// advance iterator terminals.
template<typename Expr>
struct eval<
Expr
, typename boost::enable_if<
proto::matches<Expr, proto::terminal<iterator_wrapper<_> > >
>::type
>
{
typedef void result_type;
result_type operator ()(Expr &expr, IncrementCtx const &) const
{
++proto::value(expr).it;
}
};
};
// A grammar which matches all the assignment operators,
// so we can easily disable them.
struct AssignOps
: proto::switch_<struct AssignOpsCases>
{};
// Here are the cases used by the switch_ above.
struct AssignOpsCases
{
template<typename Tag, int D = 0> struct case_ : proto::not_<_> {};
template<int D> struct case_< proto::tag::plus_assign, D > : _ {};
template<int D> struct case_< proto::tag::minus_assign, D > : _ {};
template<int D> struct case_< proto::tag::multiplies_assign, D > : _ {};
template<int D> struct case_< proto::tag::divides_assign, D > : _ {};
template<int D> struct case_< proto::tag::modulus_assign, D > : _ {};
template<int D> struct case_< proto::tag::shift_left_assign, D > : _ {};
template<int D> struct case_< proto::tag::shift_right_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_and_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_or_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_xor_assign, D > : _ {};
};
// An expression conforms to the MixedGrammar if it is a terminal or some
// op that is not an assignment op. (Assignment will be handled specially.)
struct MixedGrammar
: proto::or_<
proto::terminal<_>
, proto::and_<
proto::nary_expr<_, proto::vararg<MixedGrammar> >
, proto::not_<AssignOps>
>
>
{};
// Expressions in the MixedDomain will be wrapped in MixedExpr<>
// and must conform to the MixedGrammar
struct MixedDomain
: proto::domain<proto::generator<MixedExpr>, MixedGrammar>
{};
// Here is MixedExpr, a wrapper for expression types in the MixedDomain.
template<typename Expr>
struct MixedExpr
: proto::extends<Expr, MixedExpr<Expr>, MixedDomain>
{
explicit MixedExpr(Expr const &expr)
: MixedExpr::proto_extends(expr)
{}
private:
// hide this:
using proto::extends<Expr, MixedExpr<Expr>, MixedDomain>::operator [];
};
// Define a trait type for detecting vector and list terminals, to
// be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.
template<typename T>
struct IsMixed
: mpl::false_
{};
template<typename T, typename A>
struct IsMixed<std::list<T, A> >
: mpl::true_
{};
template<typename T, typename A>
struct IsMixed<std::vector<T, A> >
: mpl::true_
{};
namespace MixedOps
{
// This defines all the overloads to make expressions involving
// std::vector to build expression templates.
BOOST_PROTO_DEFINE_OPERATORS(IsMixed, MixedDomain)
struct assign_op
{
template<typename T, typename U>
void operator ()(T &t, U const &u) const
{
t = u;
}
};
struct plus_assign_op
{
template<typename T, typename U>
void operator ()(T &t, U const &u) const
{
t += u;
}
};
struct minus_assign_op
{
template<typename T, typename U>
void operator ()(T &t, U const &u) const
{
t -= u;
}
};
struct sin_
{
template<typename Sig>
struct result;
template<typename This, typename Arg>
struct result<This(Arg)>
: boost::remove_const<typename boost::remove_reference<Arg>::type>
{};
template<typename Arg>
Arg operator ()(Arg const &a) const
{
return std::sin(a);
}
};
template<typename A>
typename proto::result_of::make_expr<
proto::tag::function
, MixedDomain
, sin_ const
, A const &
>::type sin(A const &a)
{
return proto::make_expr<proto::tag::function, MixedDomain>(sin_(), boost::ref(a));
}
template<typename FwdIter, typename Expr, typename Op>
void evaluate(FwdIter begin, FwdIter end, Expr const &expr, Op op)
{
IncrementCtx const inc = {};
DereferenceCtx const deref = {};
typename boost::result_of<Begin(Expr const &)>::type expr2 = Begin()(expr);
for(; begin != end; ++begin)
{
op(*begin, proto::eval(expr2, deref));
proto::eval(expr2, inc);
}
}
// Add-assign to a vector from some expression.
template<typename T, typename A, typename Expr>
std::vector<T, A> &assign(std::vector<T, A> &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), assign_op());
return arr;
}
// Add-assign to a list from some expression.
template<typename T, typename A, typename Expr>
std::list<T, A> &assign(std::list<T, A> &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), assign_op());
return arr;
}
// Add-assign to a vector from some expression.
template<typename T, typename A, typename Expr>
std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op());
return arr;
}
// Add-assign to a list from some expression.
template<typename T, typename A, typename Expr>
std::list<T, A> &operator +=(std::list<T, A> &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op());
return arr;
}
// Minus-assign to a vector from some expression.
template<typename T, typename A, typename Expr>
std::vector<T, A> &operator -=(std::vector<T, A> &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op());
return arr;
}
// Minus-assign to a list from some expression.
template<typename T, typename A, typename Expr>
std::list<T, A> &operator -=(std::list<T, A> &arr, Expr const &expr)
{
evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op());
return arr;
}
}
int main()
{
using namespace MixedOps;
int n = 10;
std::vector<int> a,b,c,d;
std::list<double> e;
std::list<std::complex<double> > f;
int i;
for(i = 0;i < n; ++i)
{
a.push_back(i);
b.push_back(2*i);
c.push_back(3*i);
d.push_back(i);
e.push_back(0.0);
f.push_back(std::complex<double>(1.0, 1.0));
}
MixedOps::assign(b, 2);
MixedOps::assign(d, a + b * c);
a += if_else(d < 30, b, c);
MixedOps::assign(e, c);
e += e - 4 / (c + 1);
f -= sin(0.1 * e * std::complex<double>(0.2, 1.2));
std::list<double>::const_iterator ei = e.begin();
std::list<std::complex<double> >::const_iterator fi = f.begin();
for (i = 0; i < n; ++i)
{
std::cout
<< "a(" << i << ") = " << a[i]
<< " b(" << i << ") = " << b[i]
<< " c(" << i << ") = " << c[i]
<< " d(" << i << ") = " << d[i]
<< " e(" << i << ") = " << *ei++
<< " f(" << i << ") = " << *fi++
<< std::endl;
}
}
//]

View File

@@ -0,0 +1,102 @@
//[ RGB
///////////////////////////////////////////////////////////////////////////////
// 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 is a simple example of doing arbitrary type manipulations with proto
// transforms. It takes some expression involving primary colors and combines
// the colors according to arbitrary rules. It is a port of the RGB example
// from PETE (http://www.codesourcery.com/pooma/download.html).
#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>
namespace proto = boost::proto;
struct RedTag
{
friend std::ostream &operator <<(std::ostream &sout, RedTag)
{
return sout << "This expression is red.";
}
};
struct BlueTag
{
friend std::ostream &operator <<(std::ostream &sout, BlueTag)
{
return sout << "This expression is blue.";
}
};
struct GreenTag
{
friend std::ostream &operator <<(std::ostream &sout, GreenTag)
{
return sout << "This expression is green.";
}
};
typedef proto::terminal<RedTag>::type RedT;
typedef proto::terminal<BlueTag>::type BlueT;
typedef proto::terminal<GreenTag>::type GreenT;
struct Red;
struct Blue;
struct Green;
///////////////////////////////////////////////////////////////////////////////
// A transform that produces new colors according to some arbitrary rules:
// red & green give blue, red & blue give green, blue and green give red.
struct Red
: proto::or_<
proto::plus<Green, Blue>
, proto::plus<Blue, Green>
, proto::plus<Red, Red>
, proto::terminal<RedTag>
>
{};
struct Green
: proto::or_<
proto::plus<Red, Blue>
, proto::plus<Blue, Red>
, proto::plus<Green, Green>
, proto::terminal<GreenTag>
>
{};
struct Blue
: proto::or_<
proto::plus<Red, Green>
, proto::plus<Green, Red>
, proto::plus<Blue, Blue>
, proto::terminal<BlueTag>
>
{};
struct RGB
: proto::or_<
proto::when< Red, RedTag() >
, proto::when< Blue, BlueTag() >
, proto::when< Green, GreenTag() >
>
{};
template<typename Expr>
void printColor(Expr const & expr)
{
int i = 0; // dummy state and data parameter, not used
std::cout << RGB()(expr, i, i) << std::endl;
}
int main()
{
printColor(RedT() + GreenT());
printColor(RedT() + GreenT() + BlueT());
printColor(RedT() + (GreenT() + BlueT()));
return 0;
}
//]

View File

@@ -0,0 +1,222 @@
//[ TArray
///////////////////////////////////////////////////////////////////////////////
// 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 constructs a mini-library for linear algebra, using
// expression templates to eliminate the need for temporaries when
// adding arrays of numbers. It duplicates the TArray example from
// PETE (http://www.codesourcery.com/pooma/download.html)
#include <iostream>
#include <boost/mpl/int.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
// This grammar describes which TArray expressions
// are allowed; namely, int and array terminals
// plus, minus, multiplies and divides of TArray expressions.
struct TArrayGrammar
: proto::or_<
proto::terminal< int >
, proto::terminal< int[3] >
, proto::plus< TArrayGrammar, TArrayGrammar >
, proto::minus< TArrayGrammar, TArrayGrammar >
, proto::multiplies< TArrayGrammar, TArrayGrammar >
, proto::divides< TArrayGrammar, TArrayGrammar >
>
{};
template<typename Expr>
struct TArrayExpr;
// Tell proto that in the TArrayDomain, all
// expressions should be wrapped in TArrayExpr<> and
// must conform to the TArrayGrammar
struct TArrayDomain
: proto::domain<proto::generator<TArrayExpr>, TArrayGrammar>
{};
// Here is an evaluation context that indexes into a TArray
// expression, and combines the result.
struct TArraySubscriptCtx
: proto::callable_context< TArraySubscriptCtx const >
{
typedef int result_type;
TArraySubscriptCtx(std::ptrdiff_t i)
: i_(i)
{}
// Index array terminals with our subscript. Everything
// else will be handled by the default evaluation context.
int operator ()(proto::tag::terminal, int const (&data)[3]) const
{
return data[this->i_];
}
std::ptrdiff_t i_;
};
// Here is an evaluation context that prints a TArray expression.
struct TArrayPrintCtx
: proto::callable_context< TArrayPrintCtx const >
{
typedef std::ostream &result_type;
TArrayPrintCtx() {}
std::ostream &operator ()(proto::tag::terminal, int i) const
{
return std::cout << i;
}
std::ostream &operator ()(proto::tag::terminal, int const (&arr)[3]) const
{
return std::cout << '{' << arr[0] << ", " << arr[1] << ", " << arr[2] << '}';
}
template<typename L, typename R>
std::ostream &operator ()(proto::tag::plus, L const &l, R const &r) const
{
return std::cout << '(' << l << " + " << r << ')';
}
template<typename L, typename R>
std::ostream &operator ()(proto::tag::minus, L const &l, R const &r) const
{
return std::cout << '(' << l << " - " << r << ')';
}
template<typename L, typename R>
std::ostream &operator ()(proto::tag::multiplies, L const &l, R const &r) const
{
return std::cout << l << " * " << r;
}
template<typename L, typename R>
std::ostream &operator ()(proto::tag::divides, L const &l, R const &r) const
{
return std::cout << l << " / " << r;
}
};
// Here is the domain-specific expression wrapper, which overrides
// operator [] to evaluate the expression using the TArraySubscriptCtx.
template<typename Expr>
struct TArrayExpr
: proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain>
{
typedef proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain> base_type;
TArrayExpr( Expr const & expr = Expr() )
: base_type( expr )
{}
// Use the TArraySubscriptCtx to implement subscripting
// of a TArray expression tree.
int operator []( std::ptrdiff_t i ) const
{
TArraySubscriptCtx const ctx(i);
return proto::eval(*this, ctx);
}
// Use the TArrayPrintCtx to display a TArray expression tree.
friend std::ostream &operator <<(std::ostream &sout, TArrayExpr<Expr> const &expr)
{
TArrayPrintCtx const ctx;
return proto::eval(expr, ctx);
}
};
// Here is our TArray terminal, implemented in terms of TArrayExpr
// It is basically just an array of 3 integers.
struct TArray
: TArrayExpr< proto::terminal< int[3] >::type >
{
explicit TArray( int i = 0, int j = 0, int k = 0 )
{
(*this)[0] = i;
(*this)[1] = j;
(*this)[2] = k;
}
// Here we override operator [] to give read/write access to
// the elements of the array. (We could use the TArrayExpr
// operator [] if we made the subscript context smarter about
// returning non-const reference when appropriate.)
int &operator [](std::ptrdiff_t i)
{
return proto::value(*this)[i];
}
int const &operator [](std::ptrdiff_t i) const
{
return proto::value(*this)[i];
}
// Here we define a operator = for TArray terminals that
// takes a TArray expression.
template< typename Expr >
TArray &operator =(Expr const & expr)
{
// proto::as_expr<TArrayDomain>(expr) is the same as
// expr unless expr is an integer, in which case it
// is made into a TArrayExpr terminal first.
return this->assign(proto::as_expr<TArrayDomain>(expr));
}
template< typename Expr >
TArray &printAssign(Expr const & expr)
{
*this = expr;
std::cout << *this << " = " << expr << std::endl;
return *this;
}
private:
template< typename Expr >
TArray &assign(Expr const & expr)
{
// expr[i] here uses TArraySubscriptCtx under the covers.
(*this)[0] = expr[0];
(*this)[1] = expr[1];
(*this)[2] = expr[2];
return *this;
}
};
int main()
{
TArray a(3,1,2);
TArray b;
std::cout << a << std::endl;
std::cout << b << std::endl;
b[0] = 7; b[1] = 33; b[2] = -99;
TArray c(a);
std::cout << c << std::endl;
a = 0;
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << c << std::endl;
a = b + c;
std::cout << a << std::endl;
a.printAssign(b+c*(b + 3*c));
return 0;
}
//]

View File

@@ -0,0 +1,184 @@
//[ Vec3
///////////////////////////////////////////////////////////////////////////////
// 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 is a simple example using proto::extends to extend a terminal type with
// additional behaviors, and using custom contexts and proto::eval for
// evaluating expressions. It is a port of the Vec3 example
// from PETE (http://www.codesourcery.com/pooma/download.html).
#include <iostream>
#include <functional>
#include <boost/assert.hpp>
#include <boost/mpl/int.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/proto/proto_typeof.hpp>
#include <boost/proto/transform.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
// Here is an evaluation context that indexes into a Vec3
// expression, and combines the result.
struct Vec3SubscriptCtx
: proto::callable_context< Vec3SubscriptCtx const >
{
typedef int result_type;
Vec3SubscriptCtx(int i)
: i_(i)
{}
// Index array terminals with our subscript. Everything
// else will be handled by the default evaluation context.
int operator ()(proto::tag::terminal, int const (&arr)[3]) const
{
return arr[this->i_];
}
int i_;
};
// Here is an evaluation context that counts the number
// of Vec3 terminals in an expression.
struct CountLeavesCtx
: proto::callable_context< CountLeavesCtx, proto::null_context >
{
CountLeavesCtx()
: count(0)
{}
typedef void result_type;
void operator ()(proto::tag::terminal, int const(&)[3])
{
++this->count;
}
int count;
};
struct iplus : std::plus<int>, proto::callable {};
// Here is a transform that does the same thing as the above context.
// It demonstrates the use of the std::plus<> function object
// with the fold transform. With minor modifications, this
// transform could be used to calculate the leaf count at compile
// time, rather than at runtime.
struct CountLeaves
: proto::or_<
// match a Vec3 terminal, return 1
proto::when<proto::terminal<int[3]>, mpl::int_<1>() >
// match a terminal, return int() (which is 0)
, proto::when<proto::terminal<_>, int() >
// fold everything else, using std::plus<> to add
// the leaf count of each child to the accumulated state.
, proto::otherwise< proto::fold<_, int(), iplus(CountLeaves, proto::_state) > >
>
{};
// Here is the Vec3 struct, which is a vector of 3 integers.
struct Vec3
: proto::extends<proto::terminal<int[3]>::type, Vec3>
{
explicit Vec3(int i=0, int j=0, int k=0)
{
(*this)[0] = i;
(*this)[1] = j;
(*this)[2] = k;
}
int &operator [](int i)
{
return proto::value(*this)[i];
}
int const &operator [](int i) const
{
return proto::value(*this)[i];
}
// Here we define a operator = for Vec3 terminals that
// takes a Vec3 expression.
template< typename Expr >
Vec3 &operator =(Expr const & expr)
{
typedef Vec3SubscriptCtx const CVec3SubscriptCtx;
(*this)[0] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(0));
(*this)[1] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(1));
(*this)[2] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(2));
return *this;
}
// This copy-assign is needed because a template is never
// considered for copy assignment.
Vec3 &operator=(Vec3 const &that)
{
(*this)[0] = that[0];
(*this)[1] = that[1];
(*this)[2] = that[2];
return *this;
}
void print() const
{
std::cout << '{' << (*this)[0]
<< ", " << (*this)[1]
<< ", " << (*this)[2]
<< '}' << std::endl;
}
};
// The count_leaves() function uses the CountLeaves transform and
// to count the number of leaves in an expression.
template<typename Expr>
int count_leaves(Expr const &expr)
{
// Count the number of Vec3 terminals using the
// CountLeavesCtx evaluation context.
CountLeavesCtx ctx;
proto::eval(expr, ctx);
// This is another way to count the leaves using a transform.
int i = 0;
BOOST_ASSERT( CountLeaves()(expr, i, i) == ctx.count );
return ctx.count;
}
int main()
{
Vec3 a, b, c;
c = 4;
b[0] = -1;
b[1] = -2;
b[2] = -3;
a = b + c;
a.print();
Vec3 d;
BOOST_PROTO_AUTO(expr1, b + c);
d = expr1;
d.print();
int num = count_leaves(expr1);
std::cout << num << std::endl;
BOOST_PROTO_AUTO(expr2, b + 3 * c);
num = count_leaves(expr2);
std::cout << num << std::endl;
BOOST_PROTO_AUTO(expr3, b + c * d);
num = count_leaves(expr3);
std::cout << num << std::endl;
return 0;
}
//]

View File

@@ -0,0 +1,241 @@
//[ Vector
///////////////////////////////////////////////////////////////////////////////
// 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 is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy
// expressions using std::vector<>, a non-proto type. It is a port of the
// Vector example from PETE (http://www.codesourcery.com/pooma/download.html).
#include <vector>
#include <iostream>
#include <stdexcept>
#include <boost/mpl/bool.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/debug.hpp>
#include <boost/proto/context.hpp>
#include <boost/utility/enable_if.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
template<typename Expr>
struct VectorExpr;
// Here is an evaluation context that indexes into a std::vector
// expression and combines the result.
struct VectorSubscriptCtx
{
VectorSubscriptCtx(std::size_t i)
: i_(i)
{}
// Unless this is a vector terminal, use the
// default evaluation context
template<typename Expr, typename EnableIf = void>
struct eval
: proto::default_eval<Expr, VectorSubscriptCtx const>
{};
// Index vector terminals with our subscript.
template<typename Expr>
struct eval<
Expr
, typename boost::enable_if<
proto::matches<Expr, proto::terminal<std::vector<_, _> > >
>::type
>
{
typedef typename proto::result_of::value<Expr>::type::value_type result_type;
result_type operator ()(Expr &expr, VectorSubscriptCtx const &ctx) const
{
return proto::value(expr)[ctx.i_];
}
};
std::size_t i_;
};
// Here is an evaluation context that verifies that all the
// vectors in an expression have the same size.
struct VectorSizeCtx
{
VectorSizeCtx(std::size_t size)
: size_(size)
{}
// Unless this is a vector terminal, use the
// null evaluation context
template<typename Expr, typename EnableIf = void>
struct eval
: proto::null_eval<Expr, VectorSizeCtx const>
{};
// Index array terminals with our subscript. Everything
// else will be handled by the default evaluation context.
template<typename Expr>
struct eval<
Expr
, typename boost::enable_if<
proto::matches<Expr, proto::terminal<std::vector<_, _> > >
>::type
>
{
typedef void result_type;
result_type operator ()(Expr &expr, VectorSizeCtx const &ctx) const
{
if(ctx.size_ != proto::value(expr).size())
{
throw std::runtime_error("LHS and RHS are not compatible");
}
}
};
std::size_t size_;
};
// A grammar which matches all the assignment operators,
// so we can easily disable them.
struct AssignOps
: proto::switch_<struct AssignOpsCases>
{};
// Here are the cases used by the switch_ above.
struct AssignOpsCases
{
template<typename Tag, int D = 0> struct case_ : proto::not_<_> {};
template<int D> struct case_< proto::tag::plus_assign, D > : _ {};
template<int D> struct case_< proto::tag::minus_assign, D > : _ {};
template<int D> struct case_< proto::tag::multiplies_assign, D > : _ {};
template<int D> struct case_< proto::tag::divides_assign, D > : _ {};
template<int D> struct case_< proto::tag::modulus_assign, D > : _ {};
template<int D> struct case_< proto::tag::shift_left_assign, D > : _ {};
template<int D> struct case_< proto::tag::shift_right_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_and_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_or_assign, D > : _ {};
template<int D> struct case_< proto::tag::bitwise_xor_assign, D > : _ {};
};
// A vector grammar is a terminal or some op that is not an
// assignment op. (Assignment will be handled specially.)
struct VectorGrammar
: proto::or_<
proto::terminal<_>
, proto::and_<proto::nary_expr<_, proto::vararg<VectorGrammar> >, proto::not_<AssignOps> >
>
{};
// Expressions in the vector domain will be wrapped in VectorExpr<>
// and must conform to the VectorGrammar
struct VectorDomain
: proto::domain<proto::generator<VectorExpr>, VectorGrammar>
{};
// Here is VectorExpr, which extends a proto expr type by
// giving it an operator [] which uses the VectorSubscriptCtx
// to evaluate an expression with a given index.
template<typename Expr>
struct VectorExpr
: proto::extends<Expr, VectorExpr<Expr>, VectorDomain>
{
explicit VectorExpr(Expr const &expr)
: proto::extends<Expr, VectorExpr<Expr>, VectorDomain>(expr)
{}
// Use the VectorSubscriptCtx to implement subscripting
// of a Vector expression tree.
typename proto::result_of::eval<Expr const, VectorSubscriptCtx const>::type
operator []( std::size_t i ) const
{
VectorSubscriptCtx const ctx(i);
return proto::eval(*this, ctx);
}
};
// Define a trait type for detecting vector terminals, to
// be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.
template<typename T>
struct IsVector
: mpl::false_
{};
template<typename T, typename A>
struct IsVector<std::vector<T, A> >
: mpl::true_
{};
namespace VectorOps
{
// This defines all the overloads to make expressions involving
// std::vector to build expression templates.
BOOST_PROTO_DEFINE_OPERATORS(IsVector, VectorDomain)
typedef VectorSubscriptCtx const CVectorSubscriptCtx;
// Assign to a vector from some expression.
template<typename T, typename A, typename Expr>
std::vector<T, A> &assign(std::vector<T, A> &arr, Expr const &expr)
{
VectorSizeCtx const size(arr.size());
proto::eval(proto::as_expr<VectorDomain>(expr), size); // will throw if the sizes don't match
for(std::size_t i = 0; i < arr.size(); ++i)
{
arr[i] = proto::as_expr<VectorDomain>(expr)[i];
}
return arr;
}
// Add-assign to a vector from some expression.
template<typename T, typename A, typename Expr>
std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr)
{
VectorSizeCtx const size(arr.size());
proto::eval(proto::as_expr<VectorDomain>(expr), size); // will throw if the sizes don't match
for(std::size_t i = 0; i < arr.size(); ++i)
{
arr[i] += proto::as_expr<VectorDomain>(expr)[i];
}
return arr;
}
}
int main()
{
using namespace VectorOps;
int i;
const int n = 10;
std::vector<int> a,b,c,d;
std::vector<double> e(n);
for (i = 0; i < n; ++i)
{
a.push_back(i);
b.push_back(2*i);
c.push_back(3*i);
d.push_back(i);
}
VectorOps::assign(b, 2);
VectorOps::assign(d, a + b * c);
a += if_else(d < 30, b, c);
VectorOps::assign(e, c);
e += e - 4 / (c + 1);
for (i = 0; i < n; ++i)
{
std::cout
<< " a(" << i << ") = " << a[i]
<< " b(" << i << ") = " << b[i]
<< " c(" << i << ") = " << c[i]
<< " d(" << i << ") = " << d[i]
<< " e(" << i << ") = " << e[i]
<< std::endl;
}
}
//]

View File

@@ -0,0 +1,306 @@
//[ VirtualMember
// 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 demonstrates how to use BOOST_PROTO_EXTENDS_MEMBERS()
// to add "virtual" data members to expressions within a domain. For
// instance, with Phoenix you can create a lambda expression such as
//
// if_(_1 > 0)[ std::cout << _2 ].else_[ std::cout << _3 ]
//
// In the above expression, "else_" is a so-called virtual data member
// of the expression "if_(_1 > 0)[ std::cout << _2 ]". This example
// shows how to implement the ".else_" syntax with Proto.
//
// ****WARNING****WARNING****WARNING****WARNING****WARNING****WARNING****
// * The virtual data member feature is experimental and can change at *
// * any time. Use it at your own risk. *
// **********************************************************************
#if defined(_MSC_VER) && _MSC_VER == 1310
#error "Sorry, this example doesn\'t work with MSVC 7.1"
#endif
#include <iostream>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/min_max.hpp>
#include <boost/mpl/next_prior.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/typeof/std/ostream.hpp>
#include <boost/proto/proto.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace fusion = boost::fusion;
using proto::_;
namespace mini_lambda
{
// A callable PolymorphicFunctionObject that wraps
// fusion::at()
struct at : proto::callable
{
template<class Sig>
struct result;
template<class This, class Vector, class N>
struct result<This(Vector, N)>
: fusion::result_of::at<
typename boost::remove_reference<Vector>::type
, typename boost::remove_reference<N>::type
>
{};
template<class Vector, class N>
typename fusion::result_of::at<Vector const, N>::type
operator()(Vector const &vector, N) const
{
return fusion::at<N>(vector);
}
};
// An MPL IntegralConstant
template<class N>
struct placeholder
{
typedef N type;
typedef typename N::tag tag;
typedef typename N::next next;
typedef typename N::prior prior;
typedef typename N::value_type value_type;
static const value_type value = N::value;
};
// Some keyword types for our lambda EDSL
namespace keyword
{
struct if_ {};
struct else_ {};
struct do_ {};
struct while_ {};
struct try_ {};
struct catch_ {};
}
// Forward declaration for the mini-lambda grammar
struct eval_if_else;
// Forward declaration for the mini-lambda expression wrapper
template<class E>
struct expression;
// The grammar for mini-lambda expressions with transforms for
// evaluating the lambda expression.
struct grammar
: proto::or_<
// When evaluating a placeholder, use the placeholder
// to index into the "data" parameter, which is a fusion
// vector containing the arguments to the lambda expression.
proto::when<
proto::terminal<placeholder<_> >
, at(proto::_data, proto::_value)
>
// When evaluating if/then/else expressions of the form
// "if_( E0 )[ E1 ].else_[ E2 ]", pass E0, E1 and E2 to
// eval_if_else along with the "data" parameter. Note the
// use of proto::member<> to match binary expressions like
// "X.Y" where "Y" is a virtual data member.
, proto::when<
proto::subscript<
proto::member<
proto::subscript<
proto::function<
proto::terminal<keyword::if_>
, grammar
>
, grammar
>
, proto::terminal<keyword::else_>
>
, grammar
>
, eval_if_else(
proto::_right(proto::_left(proto::_left(proto::_left)))
, proto::_right(proto::_left(proto::_left))
, proto::_right
, proto::_data
)
>
, proto::otherwise<
proto::_default<grammar>
>
>
{};
// A callable PolymorphicFunctionObject that evaluates
// if/then/else expressions.
struct eval_if_else : proto::callable
{
typedef void result_type;
template<typename If, typename Then, typename Else, typename Args>
void operator()(If const &if_, Then const &then_, Else const &else_, Args const &args) const
{
if(grammar()(if_, 0, args))
{
grammar()(then_, 0, args);
}
else
{
grammar()(else_, 0, args);
}
}
};
// Define the mini-lambda domain, in which all expressions are
// wrapped in mini_lambda::expression.
struct domain
: proto::domain<proto::pod_generator<expression> >
{};
// A simple transform for computing the arity of
// a lambda expression.
struct arity_of
: proto::or_<
proto::when<
proto::terminal< placeholder<_> >
, mpl::next<proto::_value>()
>
, proto::when<
proto::terminal<_>
, mpl::int_<0>()
>
, proto::otherwise<
proto::fold<
_
, mpl::int_<0>()
, mpl::max<arity_of, proto::_state>()
>
>
>
{};
// Here is the mini-lambda expression wrapper. It serves two purposes:
// 1) To define operator() overloads that evaluate the lambda expression, and
// 2) To define virtual data members like "else_" so that we can write
// expressions like "if_(X)[Y].else_[Z]".
template<class E>
struct expression
{
BOOST_PROTO_BASIC_EXTENDS(E, expression<E>, domain)
BOOST_PROTO_EXTENDS_ASSIGN()
BOOST_PROTO_EXTENDS_SUBSCRIPT()
// Use BOOST_PROTO_EXTENDS_MEMBERS() to define "virtual"
// data members that all expressions in the mini-lambda
// domain will have. They can be used to create expressions
// like "if_(x)[y].else_[z]" and "do_[y].while_(z)".
BOOST_PROTO_EXTENDS_MEMBERS(
((keyword::else_, else_))
((keyword::while_, while_))
((keyword::catch_, catch_))
)
// Calculate the arity of this lambda expression
static int const arity = boost::result_of<arity_of(E)>::type::value;
// Define overloads of operator() that evaluate the lambda
// expression for up to 3 arguments.
// Don't try to compute the return type of the lambda if
// it isn't nullary.
typename mpl::eval_if_c<
0 != arity
, mpl::identity<void>
, boost::result_of<grammar(
E const &
, int const &
, fusion::vector<> &
)>
>::type
operator()() const
{
BOOST_MPL_ASSERT_RELATION(arity, ==, 0);
fusion::vector<> args;
return grammar()(proto_base(), 0, args);
}
#define BOOST_PROTO_LOCAL_MACRO( \
N, typename_A, A_const_ref, A_const_ref_a, a \
) \
template<typename_A(N)> \
typename boost::result_of<grammar( \
E const & \
, int const & \
, fusion::vector<A_const_ref(N)> & \
)>::type \
operator ()(A_const_ref_a(N)) const \
{ \
BOOST_MPL_ASSERT_RELATION(arity, <=, N); \
fusion::vector<A_const_ref(N)> args(a(N)); \
return grammar()(proto_base(), 0, args); \
}
// Repeats BOOST_PROTO_LOCAL_MACRO macro for N=1 to 3
// inclusive (because there are only 3 placeholders)
#define BOOST_PROTO_LOCAL_a BOOST_PROTO_a
#define BOOST_PROTO_LOCAL_LIMITS (1, 3)
#include BOOST_PROTO_LOCAL_ITERATE()
};
namespace placeholders
{
typedef placeholder<mpl::int_<0> > _1_t;
typedef placeholder<mpl::int_<1> > _2_t;
typedef placeholder<mpl::int_<2> > _3_t;
// Define some placeholders
expression<proto::terminal<_1_t>::type> const _1 = {{{}}};
expression<proto::terminal<_2_t>::type> const _2 = {{{}}};
expression<proto::terminal<_3_t>::type> const _3 = {{{}}};
// Define the if_() statement
template<typename E>
typename proto::result_of::make_expr<proto::tag::function, domain
, keyword::if_
, E const &
>::type const
if_(E const &e)
{
return proto::make_expr<proto::tag::function, domain>(
keyword::if_()
, boost::ref(e)
);
}
}
using placeholders::if_;
}
int main()
{
using namespace mini_lambda::placeholders;
// OK, we can create if/then/else lambda expressions
// and evaluate them.
if_(_1 > 0)
[
std::cout << _2 << '\n'
]
.else_
[
std::cout << _3 << '\n'
]
(-42, "positive", "non-positive");
// Even though all expressions in the mini-lambda
// domain have members named else_, while_, and catch_,
// they all occupy the same byte in the expression.
BOOST_MPL_ASSERT_RELATION(sizeof(_1), ==, 2);
return 0;
}
//]