1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 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;
}
//]
|