template <class Temps> unsigned abnormal_count(const Temps & temps) return std::count_if( temps.begin(), temps.end(), abnormal_temperature) static bool abnormal_temperature(double temp) return (temp < 97.6) or (99.6 < temp)
template <class Temps> unsigned normal_count(const Temps & temps) return std::count_if( temps.begin(), temps.end(), std::not1( std::ptr_fun( abnormal_temperature)))
template <class Temps> unsigned abnormal_count(const Temps & temps) return std::count_if( temps.begin(), temps.end(),abnormal_temperaturet < 97.6 || 99.6 > t)
? 1 + 3 4 ? (10 + 13 + 8)/3 10.33 ?
(t < 97.6) || (99.6 < t)
.
typedef double result_type class expression public: virtual result_type evaluate() const = 0
class nilary_expression : public expression
class unary_expression : public expression protected: expression * operand
class binary_expression : public expression protected: expression * left, * right
struct literal : public nilary_expression literal(result_type v) : value(v) { } result_type evaluate() const return value private: result_type value
struct less : public binary_expression less(expression * l, expression * r) left = l right = r result_type evaluate() const return left->evaluate() < right->evaluate()
$ cat ex-test.cc #include <iostream> #include "expression.h" int main() double t = 102.3 // t < 97.6 || 99.6 < t expression * ep = new or_else( new less ( new variable(t), new literal(97.6)), new less ( new new literal(99.6), variable(t))) std::cout << t << " is " << (ep->evaluate() ? "ab" : "") << "normal.\n" $ g++ -o ex-test ex-test.cc $ ./ex-test 102.3 is abnormal $
See the complete code.
result_type or_else:: evaluate() const return left->evaluate() || right->evaluate() result_type sum:: evaluate() const return left->evaluate() + right->evaluate() result_type xor:: evaluate() const return left->evaluate() ^ right->evaluate()
left
could be a binary expression or a literal.
template <class LExpr, // Left operand's type. class RExpr, // Right operand's type. class BinOp> // Binary operator's type. struct binary_expression binary_expression( LExpr l, RExpr r, BinOp op = BinOp()) : left(l), right(r), op(op) { } result_type evaluate() const return op(left.evaluate(), right.evaluate()) private: LExpr left RExpr right BinOp op
typedef double result_type struct literal literal(result_type v) : value(v) { } result_type evaluate() const return value private: result_type value struct variable variable(result_type & v) : var(v) { } result_type evaluate() const return var private: result_type var
$ cat et-test.cc #include <iostream> #include <functional> #include "expression.h" int main() result_type t = 102.5 // (t < 97.6) || (99.6 < t) const bool abnormal = binary_expression< binary_expression <variable, literal, std::less<result_type> >, binary_expression <literal, variable, std::less<result_type> >, std::logical_or<result_type> > (binary_expression <variable, literal, std::less<result_type> > (variable(t), literal(97.6)), binary_expression <literal, variable, std::less<result_type> > (literal(99.6), variable(t))).evaluate() std::cout << t << " is " << (abnormal ? "ab" : "") << "normal.\n"
(t < 97.6) || (99.6 < t)
.
binary_expression <binary_expression <variable, literal, std::less<rtype> >, binary_expression <literal, variable, std::less<rtype> >, std::logical_or<result_type> > (binary_expression <variable, literal, std::less<result_type> > (variable(t), literal(97.6)), binary_expression <literal, variable, std::less<result_type> > (literal(99.6), variable(t) )
$ g++ -o et-test et-test.cc $ ./et-test 102.5 is abnormal. $ CC -o et-test et-test.cc $ ./et-test 102.5 is abnormal. $
evaluate()
?
for this scheme to work well.
template <class LExpr, class RExpr> binary_expression <LExpr, RExpr, std::less<rtype> > make_less(LExpr l, RExpr r) return binary_expression <LExpr, RExpr, std::less<rtype> > (l, r) templatebinary_expression <LExpr, RExpr, std::logical_or<rtype> > make_logical_or(LExpr l, RExpr r) return binary_expression <LExpr, RExpr, std::logical_or<rtype> > (l, r)
const bool abnormal = make_logical_or( make_less(variable(t), literal(97.6)), make_less(literal(99.6), variable(t)) ).evaluate()
make_less(variable(t), literal(97.6))
resolves to the template function
template <class LExpr, class RExpr> binary_expression <LExpr, RExpr, std::less<rtype> > make_less(LExpr l, RExpr r) return binary_expression <LExpr, RExpr, std::less<rtype> > (l, r)
with LExpr
binding to variable
and RExpr
binding to
literal
.
template <class LExpr, class RExpr> binary_expression <LExpr, RExpr, std::less<rtype> >make_less(LExpr l, RExpr r)operator < (LExpr l, RExpr r) return binary_expression <LExpr, RExpr, std::less<rtype> > (l, r) templatebinary_expression <LExpr, RExpr, std::logical_or<rtype> > make_logical_or(LExpr l, RExpr r)operator || (LExpr l, RExpr r) return binary_expression <LExpr, RExpr, std::logical_or<rtype> > (l, r)
const bool abnormal = ((variable(t) < literal(97.6)) || (literal(99.6) < variable(t))).evaluate()
variable()
calls by delaring them before hand.
return_type temp = 100 variable t = temp const bool abnormal = ((t < literal(97.6)) || (literal(99.6) < t)).evaluate()
return_type temp = 100 variable t = temp const bool abnormal = ((t < 97.6) || (99.6 < t)).evaluate()
what is the type of t < 97.6
?
binary_expression <variable, double, std::less<result_type> >
evaluate()
.
literal::literal(return_type v)
is a cast conversion.
double -> literal
struct double_representation typedef literal type
double_representation::type
struct literal_representation typedef literal type struct variable_representation typedef variable type struct unary_expression_representation typedef unary_expression type struct binary_expression_representation typedef binary_expression type
template < class ExprType > struct representation typedef ExprType type
T
is
representation<T>::type
and is the same as T
.
template < > struct representation<int> typedef literal type template < > struct representation<double> typedef literal type // and so on for bool, short, ...
T
is
representation<T>::type
and is the same as literal literal
.
representation<double>::type
resolves to
template <class ValueType> struct representation typedef ValueType type
with ValueType
as double
, and to
template < > struct representation<double> typedef literal type
but the latter is more specific.
template <class LExpr, // Left operand's type. class RExpr, // Right operand's type. class BinOp> // Binary operator's type. struct binary_expression binary_expression( LExpr l, RExpr r, BinOp op = BinOp()) : left(l), right(r), op(op) { } result_type evaluate() const return op(left.evaluate(), right.evaluate()) private:LExpr lefttypename representation<LExpr>::type leftRExpr righttypename representation<RExpr>::type right BinOp op
t < 101.5
with t
declared a variable.
binary_expression <variable, double, std::less<result_type> >
right
has type
typename representation<RExpr>::type
RExpr
is double
, representationtemplate < > representation<double> typedef literal type
right
has type literal
.
right(r)
converts the double 101.5
to the
literal right
.
$ cat et-traits.cc int main() result_type temp = 450.0 variable t = temp const bool abnormal = ((t < 97.6) || (99.6 < t)).evaluate() std::cout << temp << " is " << (abnormal ? "ab" : "") << "normal.\n" $ g++ -o et-traits et-traits.cc $ ./et-traits 450 is abnormal. $
evaluate()
.
result_value literal::evaluate(result_value) return v
result_value variable::evaluate(result_value v)return varreturn v
result_value binary_expression:: evaluate(result_value v) return operator(left.evaluate(), right.evaluate()left.evaluate(v), right.evaluate(v))
$ cat et-lambda.cc template < class Expression > static result_type find_max(Expression expr, double l, double r, double s) result_type mx = expr.evaluate(l) while l < r mx = std::max(expr.evaluate(l), mx) l += s return mx int main() variable x std::cout << find_max((x - 3)*(x - 5), 1, 10, 1) << "\n" << find_max((x - 3)/(x + 5), 1, 10, 1) << "\n" $ g++ -o et-lambda et-lambda.cc $ ./et-lambda 24 0.428571 $
evaluate()
into a call operator.
result_value literal::operator () (result_value) return v result_value variable::operator () (result_value v) return v result_value binary_expression:: operator () (result_value v) returnop(left.evaluate(v), right.evaluate(v))op(left(v), right(v))
$ cat et-callable.cc template <class Temps> static unsigned abnormal_count(const Temps & temps) variable t return std::count_if( temps.begin(), temps.end(), (t < 97.6) || (99.6 < t)) int main() double temps[] = { 95, 96, 97, 98, 99, 100, 101} std::vectort(temps, temps + 7) std::cout << abnormal_count(t) << " abnormal temperatures.\n" $ g++ -o et-callable et-callable.cc $ ./et-callable 5 abnormal temperatures. $
These notes were derived from this article.
The Boost Lambda Library.
An industrial-strength implementation of the ideas discussed here.
This page last modified on 6 May 2004.