我还在学习c++,并为它写了一个粒子模拟库。我想尽可能地优化我的工作代码,我的下一个瓶颈是我的向量运算符。
我创建了一个模板vector类,它依赖于vector中包含的类型和维度:
template<typename T, unsigned int D>
class Vector {
private:
T values[D];
}
我的操作符是这样定义的:
template<typename T, unsigned int D>
Vector<T, D> operator+(const Vector<T, D>& v1, const Vector<T, D>& v2) {
T values [D];
for(unsigned int i = 0; i < D; i++) {
values[i] = v1[i] + v2[i];
}
return Vector<T, D>(values);
}
在我的模拟中,我最终做了很多向量计算,我想尝试优化它。
我的第一个假设是,如果我事先知道维度,我可以摆脱循环,得到这样的东西:
T values[3];
values[0] = v1[0] + v2[0];
values[1] = v1[1] + v2[1];
values[2] = v1[2] + v2[2];
return Vector<T, 3>(values);
所以我想到了一个递归宏,看起来像这样:
#define vec_sum(D, values, v1, v2) if D > 0 {
vec_sum(D-1, values, v1, v2)
values[D-1] = v1[D-1] + v2[D-1];
} else {
values[0] = v1[0] + v2[0];
}
然后,我的函数看起来像这样:
template<typename T, unsigned int D>
Vector<T, D> operator+(const Vector<T, D>& v1, const Vector<T, D>& v2) {
T values [D];
vec_sum(D, values, v1, v2)
return Vector<T, D>(values);
}
这样的代码生成可以用c++实现吗?
3条答案
按热度按时间ssgvzors1#
用手做是没有意义的。编译器可以将循环展开本身作为优化步骤。
在正确阅读生成的程序集和基准测试之后,如果您注意到编译器没有进行理想优化,则可以向循环添加编译器特定的属性,以通知编译器展开它。
展开是否有益也是不明显的,并且取决于确切的情况。如果您没有进行过基准测试,也没有更深入地了解您正在编译的架构/CPU,那么不要默认地认为它必须具有更高的性能。
hgb9j2n62#
如果启用编译器优化,通常不会获得任何好处。
如果你想这样做,你可以在不使用宏的情况下使用一个助手函数
std::index_sequence
和一个折叠表达式(需要C++17):llycmphe3#
我建议你使用constexpr技术,并使
vec_sum
宏成为一个constexpr函数。预处理器宏的第一个问题是,它在模板示例化之前展开。其次,宏不能递归地工作。这意味着,
vec_sum(D-1, values, v1, v2)
将无法工作,并且您的编译器很可能会抱怨您调用了未定义的函数vec_sum(D-1, values, v1, v2)
,或者抱怨缺少标记。