I am trying to write a library using expression templates, and I need to find a way to assign the expression in an variable without evaluating it (which is what I've found in every resource, eg
Wikipedia ). Also, since I want to do this for different types of expressions, I need some kind of type erasure.
I tried to do this in a simple example, using lambdas as members, but I often get Segfault.
What I have tried:
In the code below, I have defined Number and Addition class, as the basis for what I am trying to do. Also, I define an Expression class that allows me to use Expression variables to store combinations of Number and Addition expressions.
#include<iostream>
#include<functional>
#include<vector>
#define msg std::cout<<typeid(*this).name()<<std::endl
class Expression{
public:
std::function<double(void)> evaluate;
template<typename T>
Expression(const T &RH){evaluate = RH.evaluate;}
template<typename T>
Expression& operator=(const T &RH)
{evaluate = RH.evaluate; return *this;}
};
class Number{
double val;
public:
Number()=default;
std::function<double()> evaluate;
Number(const double &x):val(x)
{evaluate = [this](){msg; return this->val;}; }
Number(const Number &x):val(x.evaluate())
{evaluate = [this](){msg; return this->val;}; }
};
template<typename leftHand,typename rightHand>
class Addition{
const leftHand &LH;
const rightHand &RH;
public:
std::function<double()> evaluate;
Addition(const leftHand &LH, const rightHand &RH):LH(LH),RH(RH){
evaluate = [this]()
{msg; return this->LH.evaluate() + this->RH.evaluate();};
}
};
template<typename leftHand,typename rightHand>
auto operator+(const leftHand &LH, const rightHand &RH)
{return Addition<leftHand,rightHand>(LH,RH); }
using std::cout;
using std::endl;
inline Expression func (std::vector<Expression> x, int i){
cout<<i<<endl;
if (i==0){return static_cast<Expression>(x[0]);}
return static_cast<Expression>( x[i] + func(x,i-1) ) ;
};
int main(){
Number y(-2.);
Number x(1.33);
Expression z(y+x);
Expression w(x+y+x);
z =x;
cout<<z.evaluate()<<endl;
cout<<(z+z+z+z).evaluate()<<endl;
return 0;
}
I also tried doing something similar using CRTP + Polymorphic cloning, but I get similar behavior:
#include<iostream>
#include<memory>
#define msg std::cout<<typeid(*this).name()<<std::endl;
struct BaseExpression{
BaseExpression()=default;
virtual double evaluate()const =0 ;
};
template<typename subExpr>
struct GenericExpression:BaseExpression{
const subExpr& self() const {return static_cast<const subExpr&>(*this);}
subExpr& self() {return static_cast<subExpr&>(*this);}
double evaluate() const { msg; return self().evaluate(); };
};
class Number: public GenericExpression<Number>{
double val;
public:
Number()=default;
Number(const double &x):val(x){}
Number(const Number &x):val(x.evaluate()){}
Number(Number *x):val(x->evaluate()){}
double evaluate()const { msg; return val;}
double& evaluate() { msg; return val;}
};
template<typename leftHand,typename rightHand>
class Addition:public GenericExpression<Addition<leftHand,rightHand>>{
const leftHand &LH;
const rightHand &RH;
public:
Addition(const leftHand &LH, const rightHand &RH):LH(LH),RH(RH){}
Addition(Addition *add):LH(add->LH),RH(add->RH){}
double evaluate() const {msg; return LH.evaluate() + RH.evaluate();}
};
template<typename leftHand,typename rightHand>
Addition<leftHand,rightHand>
operator+(const GenericExpression<leftHand> &LH, const GenericExpression<rightHand> &RH){
return Addition<leftHand,rightHand>(LH.self(),RH.self());
}
class Expression: public GenericExpression<Expression>{
public:
std::unique_ptr<BaseExpression> baseExpr;
Expression()=default;
double evaluate() const {msg; return baseExpr->evaluate();}
template<typename subExpr>
void assign(const GenericExpression<subExpr> &RH){
baseExpr = std::make_unique<subExpr>(new subExpr(RH.self()));
}
};
using std::cout;
using std::endl;
int main(){
Number x(3.2);
Number y(-2.3);
Expression z,w;
z.assign(x);
cout<<z.evaluate()<<endl;
z.assign(x+y);
cout<<z.evaluate()<<endl;
return 0;
}
Generally, what I am trying to achieve is the following:
Number x(5.),y(3.);
Expression z;
z=x;
z=z+y;
z.evaluate();
That is, assignment of an expression and possible reassignment without evaluation. I know it's too much to ask of a strongly typed language, but it feels like something C++ can do at the right hands.