Aleksander Monk
Aleksander Monk

Reputation: 2907

Pointers and references + overloaded operators

Let's say I have a program in which I want to solve equations(something like this)

Number x;
Func fw = x * 4 + x * x;
std::cout << fw(6.0) << "\n\n";

Thus, I'm starting from writing abstract Base class, where I have all what I need to solve this equation.

class Base
{
public:
    Base(){};
    virtual Base* operator*(Base& x) = 0;
    virtual Base* operator*(double x) = 0;
    virtual Base* operator+(Base& x) = 0;
};

and class Number

class Number : public Base
{
public:
    virtual Base* operator*(Base& x);
    virtual Base* operator*(double x);
    virtual Base* operator+(Base& x);
};

and class Func with copy constructor(or at least, Ithink that it's a copy constructor)

class Func: public Base
{
    Base * func;
public:
    Func(Base* other)
    {
        func = other;
    }

    Func(Base& other)
    {
        func = &other;
    }

    virtual Base* operator*(Base& x){}

    virtual Base* operator*(double x){}

    virtual Base* operator+(Base&){}

};

So, my problem. My program works for x*x or for x*4, but when I try to combine them x*x + x*4 I have a problem.

It's obvious(or it is not) what the problem is.After x*x my program is returning pointer(Base*) and in my overloaded operators I have only (Base&). So program can't match any overloaded operator to it.

Here is what CLion shows me binary operator + can't be applied to the expression of type Base* and Base*

So, solution can be to overload operators one more time but with argument(Base*), but I hope there is a better way to solve this problem. Is there?

Upvotes: 1

Views: 97

Answers (3)

user1084944
user1084944

Reputation:

Yes, there is: write a wrapper class that uses value or reference semantics rather than pointer semantics. For example,

class BaseRep // I've renamed your `Base` class
{
public:
    BaseRep(){};
    virtual std::unique_ptr<BaseRep> multiply(const BaseRep& x) = 0;
};

class Base
{
    std::unique_ptr<BaseRep> ptr;
public:
    Base(std::unique_ptr<BaseRep> &&p):ptr(p) {}
    BaseRep& rep() { return *ptr; }
    const BaseRep& rep() const { return *ptr; }
    // and other stuff
};

Base operator*(const Base &x, const Base &y)
{
    return Base( x.rep().multiply(y.rep()) );
}

Upvotes: 1

Edward Strange
Edward Strange

Reputation: 40859

template < size_t Index >
struct placeholder {
    template < typename ... Args >
    auto operator()(Args ... args) const
    {
        auto tpl = std::make_tuple(args...);
        return get<Index>(tpl);
    }

 };

 placeholder<0> _1;
 placeholder<1> _2; // etc...

 template < typename T >
 struct val
 {
    T value;
    val(T v) : value(v) {}

    template < typename ... Args >
    auto operator()(Args ... ) const { return value; }
 };

 template < typename LH, typename RH >
 struct plus_operator
 {
     plus_operator(LH l, RH r) : lh(l), rh(r) {}

     LH lh;
     RH rh;

    template < typename ... Args >
    auto operator()(Args ... args) const { return lh(args...) + rh(args...); }
 };

 template < size_t I, typename T >
 auto operator + (placeholder<I> lh, T rh)
 {
     return plus_operator<placeholder<I>,T>{lh,val<T>{rh}};
 }
 template < typename T, size_t I >
 auto operator + (T lh, placeholder<I> rh) ...
 // because this would otherwise be ambiguous...
 template < size_t I1, size_t I2 >
 auto operator + (placeholder<I1> lh, placeholder<I2> rh) ...

Same same for *, -, /...

 auto fun = _1 * 4 + _1 * _1;

 auto result = fun(5);

Not tested. No warranty. But this technique is I believe what you want to solve the problem. It's called 'expression templates'.

Oh, and you'll have to override for each possible operator being LH, RH...probably a better way using SFINAE.

Upvotes: 0

Richard Hodges
Richard Hodges

Reputation: 69864

all arithmetic operators should return a reference (or a copy), absolutely not a pointer.

Upvotes: 0

Related Questions