假设我有以下内容:
struct point
{
double x;
double y;
double z;
};我可以写下以下代码:
void point_mult(point& p, double c) { p.x *= c; p.y *= c; p.z *= c; }
void point_add(point& p, const point& p2) { p.x += p2.x; p.y += p2.y; p.z += p2.z; }因此,我可以执行以下操作:
point p{1,2,3};
point_mult(p, 2);
point_add(p, point{4,5,6});这不需要point的副本,只需要两个构造,即构造point{1,2,3}和构造point{4,5,6}。我相信,即使point_add、point_mult和point{...}位于不同的编译单元中(即不能内联),这一点也适用。
但是,我想以一种更函数式的方式编写代码,如下所示:
point p = point_add(point_mult(point{1,2,3}, 2), point{4,5,6});我如何编写point_mult和point_add,使其不需要副本(即使point_mult和point_add位于不同的编译单元中),或者函数风格在C++中不是很有效?
发布于 2012-02-29 15:34:11
让我们忽略这个问题的隐含谬误(即复制自动意味着效率降低)。让我们忽略这样一个问题:是否真的会发生任何复制,或者是否所有复制都会被任何不太像样的编译器省略掉。让我们从表面上看:这可以在不复制的情况下完成吗?
是的,这可能是r-value引用的唯一其他合法用途(尽管之前被忽略的规定使得这个用例值得怀疑):
point &&point_mult(point &&p, double c);当然,这只会绑定到临时对象。因此,您将需要一个替代版本的l值:
point &point_mult(point &p, double c);关键是,您可以按原样传递引用,或者作为对临时变量的引用,或者作为对l值的引用。
发布于 2012-02-29 14:56:16
它可以用非常难看的模板元编程来完成。例如,eigen使用模板,因此像matrix1 + matrix2 * matrix3这样的表达式不需要创建任何临时变量。它的工作原理是,矩阵的+和*运算符不返回Matrix对象,而是返回某种矩阵表达式对象,该对象根据表达式参数的类型进行模板化。然后,此矩阵表达式对象可以仅在需要时计算表达式的某些部分,而不是创建临时对象来存储子表达式的结果。
实际上,实现这一点可能会变得相当混乱。如果你感兴趣,可以看看Eigen的源码。Boost的uBlas也做了类似的事情,尽管它不像eigen那样广泛。
发布于 2012-02-29 15:01:16
一种有效的(且通用的)技术是表达式模板。你可以阅读一个很好的介绍性解释here。
它很难实现,而且是基于模板的,你不能使用单独的编译单元,但它非常有效。符号计算中一个有趣的应用是解析: Boost.Spirit在解析的基础上构建了非常高效的解析器。
C++11 auto关键字有助于在实际编程任务中使用,在处理复杂类型时一如既往,请参阅this other answer。
https://stackoverflow.com/questions/9494619
复制相似问题