views:

99

answers:

5

Hello guys,

at the moment I'm really interested in expression templates and want to code a library for writing and differentiating mathematical functions with a lambda-style syntax. At the moment, I'm able to write (_x * _x)(2); and get the correct result 4. But I would really like to do something like MathFunction f = _x * _x; f(2);, but I don't have any ideas on how to cope with the recursive expression templates on the right side. Is it possible to achieve this without using the 'auto'-Keyword instead of MathFunction or having to make the operator() virtual?

Thanks for your help!

+1  A: 

Well, Boost already supports this functionality already, so you may want to take a look at how they have done it.

The following links were really helpful when I was learning:
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Expression-template
http://www.angelikalanger.com/Articles/Cuj/ExpressionTemplates/ExpressionTemplates.htm http://www.flipcode.com/archives/Faster_Vector_Math_Using_Templates.shtml

The second link is my personal favourite!

All the best.

batbrat
Thanks for this answer and the links! I already scanned the Boost.Lambda documentation for a solution to my problem, but I didn't found a line where those lambda functions are actually "stored", they are always used inline. At the moment, I use the "C++ Templates - The Definite Guide" approach to expression templates.
UncaughtException
Uncaught exception, I was suggesting that you look at the source code. Have you looked already?
batbrat
+2  A: 

.

template<class T, class R>
struct MathFuncBase
{
   virtual R operator()(const T & v) = 0;
   virtual ~MathFuncBase() {}
};

tempate<class T, class R, class Func>
struct MathFunc : MathFuncBase<T, R>
{
   MathFunc(Func func) : func(func) {}
   virtual R operator()(const T & v) {
       return func(v);           
   }
private:
   Func func;
};

tempate<class T, class R, class Func>
boost::shared_ptr<MathFuncBase<T, R> > GetMathFunc(Func func) {
    return boost::shared_ptr<MathFuncBase<T, R> >(new MathFunc<T, R, Func> (func));
}

int main () {
    boost::shared_ptr<MathFuncBase<int, int> > f = GetMathFunc<int,int> (_x * _x);
    return (*f)(2);   
}
Alexey Malistov
`MathFuncBase` destructor should be virtual for your use case. Else when the `shared_ptr` goes out of scope it will have undefined behavior.
David Rodríguez - dribeas
virtual destructor is good. But in the case of `shared_ptr` it's not needed. Check this.
Alexey Malistov
I guess you meant to provide a reference that got lost somewhere... anyway, with `shared_ptr` you can provide your own deleter as a parameter to the constructor, but in the code block above you were not providing it. If you do not provide the second argument to the `shared_ptr` constructor, on destruction it will call `delete` on the type of the stored pointer (`MathFuncBase`). In this particular case, the UB would most probably not have any (bad) effect (neither the base nor the derived objects contain any members or perform any initialization or destruction) but it is nevertheless UB.
David Rodríguez - dribeas
@David Rodríguez: `on destruction it will call delete on the type of the stored pointer` is not true. On destruction it will call delete on the type of the template pointer passed as the first argument (`MathFunc`, not base class). Just check.
Alexey Malistov
After spending a few minutes back and forth in the implementation of `boost::shared_ptr` you are right. I had the wrong idead. I would upvote again the answer if I were allowed to :) Thanks for pointing out.
David Rodríguez - dribeas
@Alexey, i think you forgot to pass the `Func` template parameter to `MathFunc`. Otherwise i think it's a good answer but the questioner doesn't want to use virtual functions. :)
Johannes Schaub - litb
A: 

I doubt that this is possible without a virtual function. You need to do type erasure since you can't use auto and similar. But then later on in that scope since you are calling a function on the type erasured object you need runtime support to invoke a function on the derived class object.

I suspect without auto you can't do it.

Johannes Schaub - litb
A: 

As I'm a newbie to this site, I have found this not until I submitted this question. Thanks for your answers, but this is what I was really looking for.

UncaughtException
+1  A: 

Actually I don't think there is a simple way to store them. If I wanted to create a named instance of boost::lambda expression, I would assign the result to, say, int and then copy the name of the needed type from the compiler's error message:

#include <boost/lambda/lambda.hpp>

int main()
{
    using namespace boost::lambda;
    //int x = _1 + _2;
    boost::lambda::lambda_functor<boost::lambda::lambda_functor_base<
    boost::lambda::arithmetic_action<boost::lambda::plus_action>, 
    boost::tuples::tuple<boost::lambda::lambda_functor<boost::lambda::placeholder<1> >, 
    boost::lambda::lambda_functor<boost::lambda::placeholder<2> >, 
    boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, 
    boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, 
    boost::tuples::null_type, boost::tuples::null_type> > > x = _1 + _2;
}

In real life you'd be more likely to store them in a type, that does type erasure, like boost::function.

#include <boost/lambda/lambda.hpp>
#include <boost/function.hpp>   
int main()
{
    using namespace boost::lambda;
    boost::function<int(int, int)> x = _1 + _2;
    return x(-1, 1);
}
visitor