[英]C++ array operator overhead
我记得前一段时间读过一些代码,这些代码使编译器可以执行一些工作并简化这样的表达式:
// edit: yes the parameters where meant to be passed by reference
// and maintain constness sorry !
template< typename T >
std::vector<T> operator+( const std::vector<T>& a, const std::vector<T>& b )
{
assert( a.size() == b.size() );
std::vector<T> o; o.reserve( a.size() );
for( std::vector<T>::size_type i = 0; i < a.size(); ++i )
o[i] = a[i] + b[i];
return o;
}
// same for operator* but a[i] * b[i] instead
std::vector<double> a, b, c, d, e;
// do some initialization of the vectors
e = a * b + c * d
通常情况下,将为每个运算符创建并分配一个新的向量,而编译器将只创建一个副本并对其执行所有操作。
这是什么技术?
正如@Agnew刚提到的那样, 您所描述的技术是表达式模板 。
通常使用向量1而非std::vector
的数学概念来完成此操作。 广泛的招是:
向量上没有数学运算会返回结果。 而是让它们返回一个代表最终需要完成的操作的代理对象 。 a * b
可以返回一个“乘法代理”对象,该对象仅包含对应该相乘的两个向量的const引用。
还要为这些代理编写数学运算,从而允许将它们链接在一起,因此a * b + c * d
变为(TempMulProxy) + (TempMulProxy)
变为(TempAddProxy)
,而无需进行任何数学运算或复制任何矢量。
编写一个赋值运算符,将您的代理对象用作右侧对象。 该运算符可以看到整个表达式a * b + c * d
,并在知道目标位置的同时对向量有效地执行该操作。 全部不创建多个临时矢量对象。
1或矩阵或四元数等... *
我在这里没有问题。 但是,我的水晶球告诉我,您想知道您想出的两种方法中的更好方法,以便对像a * b + c * d
向量执行基于分量的算术运算,其中a
, b
, c
和d
为具有相同大小的向量( std::vector<T>
):
对于每个要执行的操作,循环遍历元素,执行计算并返回结果向量。 将这些运算放到向量公式中。
对于输入向量中的每个元素,计算整个表达式并将其写入单个最终结果向量。
有两件事要考虑:
但是,有一个不错的选项可以实现看起来非常漂亮的第二个选项:
std::vector<int> a, b, c, d, e;
// fill a, b, c, d with data
auto expression = [](int a, int b, int c, int d){ return a * b + c * d; };
assert (a.size() == b.size() && b.size() == c.size() && c.size() == d.size());
e.reserve(a.size());
for(auto _a = a.begin(), _b = b.begin(), _c = c.begin(), _d = d.begin(), _e = e.begin();
_a != a.end();
++_a, ++_b, ++_c, ++_d, ++_e)
{
*_e = expression(*_a, *_b, *_c, *_d);
}
这样,您可以将表达式与逻辑分离以对其求值:
void componentWise4(std::function<int(int,int,int,int)> f,
const std::vector<int> & a,
const std::vector<int> & b,
const std::vector<int> & c,
const std::vector<int> & d,
std::vector<int> & result)
{
assert (a.size() == b.size() && b.size() == c.size() && c.size() == d.size());
result.reserve(a.size());
for(auto _a = a.begin(), _b = b.begin(), _c = c.begin(), _d = d.begin(), _result = result.begin();
_a != a.end();
++_a, ++_b, ++_c, ++_d, ++_result)
{
*_result = expression(*_a, *_b, *_c, *_d);
}
}
然后这样称呼它:
std::vector<int> a, b, c, d, e;
// fill a, b, c, d with data
componentWise4([](int a, int b, int c, int d){ return a * b + c * d; },
a, b, c, d, e);
我确信可以使用C ++ 11的新功能“变量模板”来扩展此“表达式评估器”,以支持表达式中的任意数量的参数,甚至支持不同的类型。 我无法使其正常运行(可变参数模板),您可以尝试在此处完成我的尝试: http : //ideone.com/w88kuG (我是可变参数模板的新手,所以我不知道句法)。
您想要的是“ C ++编程语言”。 Bjarne Stroustrup在22.4.7临时,复制和循环中的第三版[num.matrix]。 读书总是一个好主意。
如果您没有,基本上我们有两个选择:
首先:我们编写了一组函数,用于直接计算一些最期望的组合(例如mul_add_and_assign(&U,&M,&V,&W)来计算U = M * V + W),并让用户选择自己需要的函数他最方便吗
其次:我们可以引入一些辅助类(例如VxV
, VplusV
等),这些辅助类仅保留对每个操作的参数的引用,并定义将运算符转换为vector
。 现在,我们创建运算符+
和*
重载,这些重载通过引用获取两个向量,并仅返回对应类型的对象。 我们可以创建VxVplusVxV
类型的VxVplusVxV
来计算更复杂的操作。 现在我们可以重载operator=
来将VxVplusVxV
一个vector
。 在最后的重载中,我们使用对辅助类对象中保留的参数的引用进行了所有计算,没有创建或创建了最小的临时向量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.