...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
boost::proto::context::callable_context — An evaluation context adaptor that makes authoring a context a simple matter of writing function overloads, rather then writing template specializations.
// In header: <boost/proto/context/callable.hpp>
template<typename Context,
typename DefaultCtx = proto::context::default_context>
struct callable_context {
// member classes/structs/unions
template<typename Expr, typename ThisContext = Context>
struct eval : see-below
{
};
};
proto::callable_context<>
is a base class that
implements the context protocol by passing fanned-out expression nodes to the derived
context, making it easy to customize the handling of expression types by writing function
overloads. Only those expression types needing special handling require explicit handling.
All others are dispatched to a user-specified default context,
DefaultCtx
.
proto::callable_context<>
is defined simply as:
template<typename Context, typename DefaultCtx = default_context> struct callable_context { template<typename Expr, typename ThisContext = Context> struct eval : mpl::if_< is_expr_handled_<Expr, Context>, // For exposition proto::context::callable_eval<Expr, ThisContext>, typename DefaultCtx::template eval<Expr, Context> >::type {}; };
The Boolean metafunction is_expr_handled_<>
uses
metaprogramming tricks to determine whether Context
has
an overloaded function call operator that accepts the fanned-out constituents of an
expression of type Expr
. If so, the handling of the
expression is dispatched to
proto::context::callable_eval<>
.
If not, it is dispatched to the user-specified DefaultCtx
.
Example:
// An evaluation context that increments all // integer terminals in-place. struct increment_ints : proto::context::callable_context< increment_ints const // derived context proto::context::null_context const // fall-back context > { typedef void result_type; // Handle int terminals here: void operator()(proto::tag::terminal, int &i) const { ++i; } };
With increment_ints
, we can do the following:
proto::literal<int> i = 0, j = 10; proto::eval( i - j * 3.14, increment_ints() ); assert( i.get() == 1 && j.get() == 11 );