#include <iostream>
using namespace std;;

class Expr {
public:
    virtual ~Expr() {}
    virtual int operator()(int) const = 0;
    virtual ostream &print(ostream &) const = 0; 
       // neccessaire a cause de l'operateur externe
};

ostream &operator<<(ostream &out, const Expr &e) {
    return e.print(out);
}

class Const : public Expr {
public:
    Const(int value) : value(value) {}
    int operator()(int x) const { return value; }
    ostream &print(ostream &out) const {
        return out << value;
    }
private:
    int value;
};

class X : public Expr {
public:
    int operator()(int x) const { return x; }
    ostream &print(ostream &out) const {
        return out << "x";
    }
};

class Plus : public Expr {
public:
    Plus(const Expr *e1, const Expr *e2) : e1(e1), e2(e2) {}
    int operator()(int x) const { return (*e1)(x) + (*e2)(x); }
    ostream &print(ostream &out) const {
        return e2->print((e1->print(out << "(") << " + ")) << ")";
    }
private:
    const Expr *e1;
    const Expr *e2;
};

int main() {
    X x;
    Const c2(2), c3(3);
    Plus p1(&x, &c2);
    Plus p2(&p1, &c3);
    
    cout << p2 << " applique en 3 = " << p2(3);
}
