我正在编写一个使用带有 CRTP 的表达式模板的库。源文件可以在这里找到:https ://github.com/mspraggs/pyQCD/tree/master/lib/include/base
表达式模板基于 Wikipedia 文章中关于该主题的示例。我在这里列出代码以防 Wiki 文章将来发生变化:
#include <vector>
#include <cassert>
template <typename E>
// A CRTP base class for Vecs with a size and indexing:
class VecExpression {
public:
typedef std::vector<double> container_type;
typedef container_type::size_type size_type;
typedef container_type::value_type value_type;
typedef container_type::reference reference;
size_type size() const { return static_cast<E const&>(*this).size(); }
value_type operator[](size_type i) const { return static_cast<E const&>(*this)[i]; }
operator E&() { return static_cast< E&>(*this); }
operator E const&() const { return static_cast<const E&>(*this); }
};
// The actual Vec class:
class Vec : public VecExpression<Vec> {
container_type _data;
public:
reference operator[](size_type i) { return _data[i]; }
value_type operator[](size_type i) const { return _data[i]; }
size_type size() const { return _data.size(); }
Vec(size_type n) : _data(n) {} // Construct a given size:
// Construct from any VecExpression:
template <typename E>
Vec(VecExpression<E> const& vec) {
E const& v = vec;
_data.resize(v.size());
for (size_type i = 0; i != v.size(); ++i) {
_data[i] = v[i];
}
}
};
template <typename E1, typename E2>
class VecDifference : public VecExpression<VecDifference<E1, E2> > {
E1 const& _u;
E2 const& _v;
public:
typedef Vec::size_type size_type;
typedef Vec::value_type value_type;
VecDifference(VecExpression<E1> const& u, VecExpression<E2> const& v) : _u(u), _v(v) {
assert(u.size() == v.size());
}
size_type size() const { return _v.size(); }
value_type operator[](Vec::size_type i) const { return _u[i] - _v[i]; }
};
template <typename E>
class VecScaled : public VecExpression<VecScaled<E> > {
double _alpha;
E const& _v;
public:
VecScaled(double alpha, VecExpression<E> const& v) : _alpha(alpha), _v(v) {}
Vec::size_type size() const { return _v.size(); }
Vec::value_type operator[](Vec::size_type i) const { return _alpha * _v[i]; }
};
// Now we can overload operators:
template <typename E1, typename E2>
VecDifference<E1,E2> const
operator-(VecExpression<E1> const& u, VecExpression<E2> const& v) {
return VecDifference<E1,E2>(u,v);
}
template <typename E>
VecScaled<E> const
operator*(double alpha, VecExpression<E> const& v) {
return VecScaled<E>(alpha,v);
}
我想要做的是添加另一个表达式模板,该模板允许分配给原始模板对象的一部分(上面代码中的 Vec 类,以及我链接到的代码中的 LatticeBase 类)。可能的用法:
Vec myvector(10);
Vec another_vector(5);
myvector.head(5) = another_vector; // Assign first 5 elements on myvector
myvector.head(2) = another_vector.head(2); // EDIT
因此,我将创建一个新函数 Vec::head,它将返回 Vec 对象的一部分的表达式模板。我不知道这将如何适应我目前拥有的框架。特别是我有以下问题/意见:
- 我已经看到了我想在不使用 CRTP 的表达式模板中实现的示例。在这种情况下使用 CRTP 可以获得什么?有什么意义吗?我应该放弃它并遵循我发现的其他示例吗?
- 在当前框架中,对 Vec 类中的 _data 成员的赋值由 Vec 类中的复制构造函数处理。如果我想使用 Vec::head 返回的表达式模板,这将不起作用,因为赋值发生在保存数据的类中,而不是表达式模板中。
- 我尝试在新的表达式模板中创建一个赋值运算符,但这不适用于上面的代码,因为所有表达式模板成员都是 const 引用,因此赋值运算符在编译时被删除。我可以将成员切换为值而不是引用吗?如果需要额外的存储,这会影响性能吗?这甚至可以工作(如果我更改表达式的存储副本而不是表达式本身)?
总的来说,我对如何在上面的代码中添加可用作左值的表达式模板感到困惑。对此的任何指导将不胜感激。