vendredi 25 janvier 2019

Lazy evaluation wrapper class?

What is a good way to implement a wrapper class for CRTP lazy evaluation?

Specifically, I am looking to work with delayed or lazy evaluation similar to the answers to this question and am interested in wrapping the CRTP derived classes in a generic class so that I can do something like the following:

Wrapper a = 1;      // Some type like Number<int>
Wrapper b = 2;      // Some type like Number<int>
Wrapper c = a + b;  // An expression like Add<Number<int>, Number<int>>

I think that a smart pointer wrapper makes sense, because I can use an abstract base class for the CRTP base and manage the underlying objects. So far, I've implemented an abstract Base class that has enable_shared_from_this so that I can create a shared_ptr, and a CRTPBase class that handles templated expressions and types.

class Base : public std::enable_shared_from_this<Base> {
public:
  virtual ~Base() {}
  // ... other virtual methods.

  // when we don't have the type.
  inline std::shared_ptr<Base> as_ptr() {
    return shared_from_this();
  }
};

template<typename Derived>
class CRTPBase : public Base {
public:
  // ... overridden virtual methods.

  // ... other CRTP stuff.
};

Then, the derived expressions are returned as something like:

template<typename T1, typename T2>
inline const Add<T1, T2> operator+(const CRTPBase<T1> &lhs, const CRTPBase<T2> &rhs) {
  return Add<T1, T2>(lhs, rhs);
}

I'm looking to have a Wrapper class that can take something like a Number<T>, Matrix<T> or an Add<T1, T2> or whatever derives from CRTPBase.

class Wrapper : public CRTPBase<Wrapper> {
private:
  std::shared_ptr<Base> ptr_;

public:
  // rule of zero?

  // example constructor to make a new Number<int>
  explicit inline Wrapper(int value) 
      : ptr_(std::make_shared<Number<int>>(value)) {}

  // what do these look like?
  template<typename T> Wrapper(const CRTPBase<T> &m) { ... }
  template<typename T> Wrapper(CRTPBase<T> &&m) { ... }  
  template<typename T> Wrapper &operator=(const CRTPBase<T> &m) { ... }
  template<typename T> Wrapper &operator=(CRTPBase<T> &&m) { ... }  
};

And because the wrapper also derives from CRTPBase, I can pass it around into expressions just like any other derived type. The goal here is to use the wrapper, and not the actual types.

How can I wrap the CRTP classes returned from expressions in a smart pointer? I'm not very confident with smart pointers and I'm looking for help understanding what it would look like to use them inside this wrapper class.

Currently, I've got things like:

template<typename T> Wrapper(const CRTPBase<T> &&m) 
    : ptr_(std::make_shared<T>(std::move(m))) {}

Which works (and I don't understand why), but seems wrong.

Aucun commentaire:

Enregistrer un commentaire