Какой хороший способ реализовать класс-оболочку для ленивых вычислений CRTP?
В частности, я рассчитываю работать с отложенной или ленивой оценкой, аналогичной ответам на этот вопрос , и мне интересно обернуть производные классы CRTP в общий класс, чтобы я мог сделать что-то вроде следующего :
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>>
Я думаю, что умная оболочка указателя имеет смысл, потому что я могу использовать абстрактный базовый класс для базы CRTP и управлять базовыми объектами.
До сих пор я реализовал абстрактный класс Base
, который имеет enable_shared_from_this
, чтобы я мог создать класс shared_ptr
и CRTPBase
, который обрабатывает шаблонные выражения и типы.
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.
inline Derived &derived() {
return static_cast<Derived &>(*this);
}
inline const Derived &derived() const {
return static_cast<const Derived &>(*this);
}
// ... other CRTP stuff.
};
Затем производные выражения возвращаются как что-то вроде:
template<typename T1, typename T2>
class Add : public CRTPBase<Add<T1, T2>> {
private:
const T1 &lhs_;
const T2 &rhs_;
public:
Add(const T1 &lhs, const T2 &rhs) : lhs_(lhs), rhs_(rhs) {}
}
template<typename T1, typename T2>
inline const Add<T1, T2> operator+(const CRTPBase<T1> &lhs, const CRTPBase<T2> &rhs) {
return Add<T1, T2>(lhs.derived(), rhs.derived());
}
Я ищу класс Wrapper
, который может принимать что-то вроде Number<T>
, Matrix<T>
или Add<T1, T2>
или что-либо, производное от 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) { ... }
};
И поскольку оболочка также является производной от CRTPBase
, я могу передать ее в выражения, как и любой другой производный тип. Целью здесь является использование обертки, а не фактических типов.
Как можно обернуть классы CRTP, возвращаемые из выражений, в интеллектуальный указатель? Я не очень уверен в умных указателях и ищу помощь в понимании того, как будет выглядеть их использование в этом классе-обёртке.
В настоящее время у меня есть такие вещи:
template<typename T> Wrapper(const CRTPBase<T> &&m)
: ptr_(std::make_shared<T>(std::move(m.derived()))) {}
Что работает (и я не понимаю почему), но, похоже, неправильно.