
Ok, at least one person said they were interested in seeing my idea for an equation toolkit, so here goes... The files a few hundred lines, so hopefully that's ok for this group. If I've exceed some message size, I'm sorry in advance... ======== e.cpp (client code) follows ========= #include "equation.h" #include "equation_enable_macros.h" int main() { equation::Equation a; a = _y + _z; std::cout << a(_y is 5, _z is 10) << std::endl; a = _x + 8 * (_y - _z); std::cout << a(_x is 2, _y is 3, _z is -9000.9) << std::endl; return 0; } ======== equation.h follows (the real work) ========= // Copyright Stephen Gross 2006 #ifndef api_equation #define api_equation #include <string> #include <iostream> #include <map> #include "boost/function.hpp" #include "boost/lambda/lambda.hpp" #include "boost/lambda/bind.hpp" namespace equation { class ArgTable { typedef std::map<std::string, double> MapType; public: ArgTable & setArg(const std::string & name, double val) { my_map[name] = val; return *this; } virtual double getArg (const std::string & name) const { MapType::const_iterator f = my_map.find(name); if(f == my_map.end()) { std::cout << "Error: Equation requested argument '" << name << "' which was not given." << std::endl; exit(0); } else { return f->second; } } private: MapType my_map; }; class ArgTableReporter : public ArgTable { public: virtual double getArg(const std::string & name) const { my_last_var = name; return 0; } const std::string & getLastVar() const { return my_last_var; } private: mutable std::string my_last_var; }; /// /// Represents an Equation, simply put. /// /// The idea here is that, for any Equation that takes named arguments ("x", "y", etc.) and manipulates them /// arithmetically, such an Equation can in fact be encapsulated in an Equation instance. /// /// class Equation { public: typedef boost::function1<double, const ArgTable &> FunctorType; /// @name Constructors //@{ Equation() : my_ftr(boost::lambda::constant(0)) { ; } Equation(const Equation & other) : my_ftr(other.my_ftr) { } template<typename T> Equation(const T & t) : my_ftr(t) { } //@} /// @name The underlying function that invokes the functor: //@{ double go (const ArgTable & args) const { return my_ftr(args); } //@} /// @name operator() //@{ double operator() () { return go(ArgTable()); } template<typename A1> double operator() (const A1 & a1, double v1) const { ArgTable args; ArgTableReporter names; a1(names); args.setArg(names.getLastVar(), v1); return go(args); } template<typename A1, typename A2> double operator() (const A1 & a1, double v1, const A2 & a2, double v2) const { ArgTable args; ArgTableReporter names; a1(names); args.setArg(names.getLastVar(), v1); a2(names); args.setArg(names.getLastVar(), v2); return go(args); } template<typename A1, typename A2, typename A3> double operator() (const A1 & a1, double v1, const A2 & a2, double v2, const A3 & a3, double v3) const { ArgTable args; ArgTableReporter names; a1(names); args.setArg(names.getLastVar(), v1); a2(names); args.setArg(names.getLastVar(), v2); a3(names); args.setArg(names.getLastVar(), v3); return go(args); } template<typename A1, typename A2, typename A3, typename A4> double operator() (const A1 & a1, double v1, const A2 & a2, double v2, const A3 & a3, double v3, const A4 & a4, double v4) const { ArgTable args; ArgTableReporter names; a1(names); args.setArg(names.getLastVar(), v1); a2(names); args.setArg(names.getLastVar(), v2); a3(names); args.setArg(names.getLastVar(), v3); a4(names); args.setArg(names.getLastVar(), v4); return go(args); } //@} private: FunctorType my_ftr; }; namespace Private { class Sigma { public: Sigma() : my_start(0), my_stop(0), my_iter(boost::lambda::constant(0.0)) { } Sigma(double start, double stop, const Equation & eq) : my_start((int)start), my_stop((int)stop), my_iter(eq) { } Sigma(const Sigma & other) : my_start(other.my_start), my_stop(other.my_stop), my_iter(other.my_iter) { } Sigma& operator=(const Sigma & other) { if(this != &other) { my_start = other.my_start; my_stop = other.my_stop; my_iter = other.my_iter; } return *this; } double go (const ArgTable & args) const { ArgTable newargs = args; double result = 0.0; for(int i = my_start; i <= my_stop; ++i) { newargs.setArg("i", (double)i); result += my_iter.go(newargs); } return result; } private: int my_start; int my_stop; Equation my_iter; }; /// /// Helper struct so that unary math functions can be easily macro-ified for constructing Equations. struct UnaryFunc { UnaryFunc(double (*fn) (double), const Equation::FunctorType & arg_getter) : my_fn(fn), my_arg_getter(arg_getter) { } UnaryFunc(double (*fn) (double), double v) : my_fn(fn), my_arg_getter(boost::lambda::constant(v)) { } UnaryFunc(const UnaryFunc & other) : my_fn(other.my_fn), my_arg_getter(other.my_arg_getter) { } UnaryFunc& operator=(const UnaryFunc & other) { if(this != &other) { my_fn = other.my_fn; my_arg_getter = other.my_arg_getter; } return *this; } double go(const ArgTable & args) const { return (*my_fn) (my_arg_getter(args)); } double (*my_fn) (double); Equation::FunctorType my_arg_getter; }; /// /// Helper struct so that binary math functions can be easily macro-ified for construction Equations. struct BinaryFunc { BinaryFunc( double (*fn) (double, double), const Equation::FunctorType & arg1_getter, const Equation::FunctorType & arg2_getter) : my_fn(fn), my_arg1_getter(arg1_getter), my_arg2_getter(arg2_getter) { } BinaryFunc( double (*fn) (double, double), double arg1, const Equation::FunctorType & arg2_getter) : my_fn(fn), my_arg1_getter(boost::lambda::constant(arg1)), my_arg2_getter(arg2_getter) { } BinaryFunc( double (*fn) (double, double), const Equation::FunctorType & arg1_getter, double arg2) : my_fn(fn), my_arg1_getter(arg1_getter), my_arg2_getter(boost::lambda::constant(arg2)) { } BinaryFunc( double (*fn) (double, double), double arg1, double arg2) : my_fn(fn), my_arg1_getter(boost::lambda::constant(arg1)), my_arg2_getter(boost::lambda::constant(arg2)) { } BinaryFunc(const BinaryFunc & other) : my_fn(other.my_fn), my_arg1_getter(other.my_arg1_getter), my_arg2_getter(other.my_arg2_getter) { } BinaryFunc& operator=(const BinaryFunc & other) { if(this != &other) { my_fn = other.my_fn; my_arg1_getter = other.my_arg1_getter; my_arg2_getter = other.my_arg2_getter; } return *this; } double go(const ArgTable & args) const { return (*my_fn) (my_arg1_getter(args), my_arg2_getter(args)); } double (*my_fn) (double, double); Equation::FunctorType my_arg1_getter; Equation::FunctorType my_arg2_getter; }; } // End namespace Private } // End namespace equation #define VAR(name) boost::lambda::bind<double>(&equation::ArgTable::getArg, boost::lambda::_1, std::string(#name)) #define EQ(name) boost::lambda::bind<double>(&equation::Equation::go, &name, boost::lambda::_1) #endif =========== equation_enable_macros.h follows ============ #ifndef api_equation_enable_macros #define api_equation_enable_macros // Disable macros now available: #undef api_equation_disable_macros #define is , #define _a VAR(a) #define _b VAR(b) #define _c VAR(c) #define _d VAR(d) #define _e VAR(e) #define _f VAR(f) #define _g VAR(g) #define _h VAR(h) #define _i VAR(i) #define _j VAR(j) #define _k VAR(k) #define _l VAR(l) #define _m VAR(m) #define _n VAR(n) #define _o VAR(o) #define _p VAR(p) #define _q VAR(q) #define _r VAR(r) #define _s VAR(s) #define _t VAR(t) #define _u VAR(u) #define _v VAR(v) #define _w VAR(w) #define _x VAR(x) #define _y VAR(y) #define _z VAR(z) #define _sigma(start, stop, iter) boost::lambda::bind<double> (&equation::Private::Sigma::go, equation::Private::Sigma (start, stop, iter), boost::lambda::_1) #define _sqrt(x) boost::lambda::bind<double> (&equation::Private::UnaryFunc::go, equation::Private::UnaryFunc (&sqrt, x), boost::lambda::_1) #define _pow(x, y) boost::lambda::bind<double> (&equation::Private::BinaryFunc::go, equation::Private::BinaryFunc (&pow, x, y), boost::lambda::_1) #endif ========= end of code snippets ==============