【发布时间】:2019-06-19 21:21:14
【问题描述】:
为 CRTP 惰性求值实现包装类的好方法是什么?
具体来说,我希望使用类似于this question 的答案的延迟或延迟评估,并且有兴趣将 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 基础使用抽象基类并管理底层对象。
到目前为止,我已经实现了一个具有enable_shared_from_this 的抽象Base 类,这样我就可以创建一个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()))) {}
哪个有效(我不明白为什么),但似乎是错误的。
【问题讨论】:
-
要编译
std::make_shared<T>(std::move(m)),T需要一个接受CRTPBase<T>的构造函数,它不会有一个隐式的——你必须明确地添加它。显示Add类的样子。 -
应该起作用的是
ptr_(std::make_shared<T>(static_cast<const T&&>(m)))。这将调用T的移动构造函数,它可以被隐式定义。这依赖于CRTPBase<T>不会单独出现,而是始终作为T的基类子对象的假设,因此向下转换是安全的。 -
添加了更多代码以使实现更加清晰。
-
嗯,您使用的正是我所想的
static_cast——它就在derived()内部,而不是明确地拼写出来。哪一部分你不明白,哪一部分看起来不对? -
这是调用 T 的移动构造函数吗?对我来说很奇怪,而且我的阅读方式略有不同,不会是
ptr_(std::make_shared<T>(static_cast<const T&>(m)))吗?
标签: c++ c++11 lazy-evaluation template-meta-programming