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