gpt4 book ai didi

c++ - 以 CRTP 为左值的表达式模板

转载 作者:行者123 更新时间:2023-11-30 02:44:51 26 4
gpt4 key购买 nike

我正在编写一个将表达式模板与 CRTP 结合使用的库。源文件可以在这里找到:https://github.com/mspraggs/pyQCD/tree/master/lib/include/base

表达式模板基于维基百科关于该主题的文章中给出的示例。我在这里列出代码以防将来 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 对象的一部分的表达式模板。我不知道这将如何适应我目前拥有的框架。特别是我有以下问题/意见:

  1. 我已经看到了我想在不使用 CRTP 的表达式模板中实现的目标的示例。在这种情况下使用 CRTP 有什么好处?有什么意义吗?我应该放弃它并遵循我找到的其他示例吗?
  2. 在当前框架中,对 Vec 类中_data 成员的赋值是由 Vec 类中的复制构造函数处理的。如果我想使用 Vec::head 返回的表达式模板,这将不起作用,因为赋值发生在保存数据的类中,而不是表达式模板中。
  3. 我已经尝试在新的表达式模板中创建一个赋值运算符,但是这不适用于上面的代码,因为所有表达式模板成员都是 const 引用,因此赋值运算符在编译时被删除。我可以将成员切换为值而不是引用吗?如果需要额外的存储,这会影响性能吗?这是否有效(如果我更改表达式的存储拷贝而不是表达式本身)?

总的来说,我对如何在上面的代码中添加一个可用作左值的表达式模板感到困惑。对此的任何指导将不胜感激。

最佳答案

试试这个:

#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); }
};

class VecHead;

// 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];
}
}

VecHead head(size_type s);
};

class VecHead : public VecExpression< VecHead >
{
Vec::size_type _s;
Vec& _e;
public:

typedef Vec::size_type size_type;
typedef Vec::value_type value_type;
VecHead(std::size_t s, Vec& e)
: _s(s)
, _e(e)
{
assert(_e.size() >= _s);
}

size_type size() const { return _s; }
value_type operator[](Vec::size_type i) const { assert(i < _s); return _e[i]; }

VecHead& operator = (const VecHead& rhs)
{
return operator=(static_cast<const VecExpression<VecHead>&>(rhs));
}

template <typename E>
VecHead& operator = (const VecExpression<E>& rhs)
{
assert(rhs.size() >= _s);
for (size_type i = 0; i < _s && i < rhs.size(); ++i)
_e[i] = rhs[i];
return *this;
}
};

VecHead Vec::head(size_type s)
{
VecHead aHead(s, *this);
return aHead;
}

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);
}

int main()
{
Vec myvector(10);
Vec another_vector(5);
for (int i = 0; i < 5; ++i)
another_vector[i] = i;

myvector.head(5) = another_vector; // Assign first 5 elements on myvector
assert(myvector.head(5).size() == 5);
for (int i = 0; i < 10; ++i)
{
assert(myvector[i] == (i < 5 ? static_cast<double>(i) : 0.));
}

//! Added test due to comment vec1.head(2) = vec2.head(2) doesn't work.
Vec vec1(10), vec2(10);
for (int i = 0; i < 10; ++i)
vec2[i] = 2 * (vec1[i] = i);

vec1.head(2) = vec2.head(2);
for (int i = 0; i < 10; ++i)
{
if (i < 2)
{
assert(vec1[i] == vec2[i]);
}
else
{
assert(vec1[i] != vec2[i]);
}
}

return 0;
}

关于c++ - 以 CRTP 为左值的表达式模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25064770/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com