假设我有一个 vector 长度计算函数,它有一个额外的 inc
参数(这告诉相邻元素之间的距离)。一个简单的实现是:
float calcLength(const float *v, int size, int inc) {
float l = 0;
for (int i=0; i<size*inc; i += inc) {
l += v[i]*v[i];
}
return sqrt(l);
}
现在,calcLength
可以用两种 inc
参数调用:当 inc
在编译时已知时,当它是不是。我想为 inc
(如 1)的常见编译时值优化 calcLength
版本。
所以,我会有这样的东西:
template <int C>
struct Constant {
static constexpr int value() {
return C;
}
};
struct Var {
int v;
constexpr Var(int p_v) : v(p_v) { }
constexpr int value() const {
return v;
}
};
template <typename INC>
float calcLength(const float *v, int size, INC inc) {
float l = 0;
for (int i=0; i<size*inc.value(); i += inc.value()) {
l += v[i]*v[i];
}
return sqrt(l);
}
}
因此,可以使用:
calcLength(v, size, Constant<1>()); // inc is a compile-time constant 1 here, calcLength can be vectorized
或
int inc = <some_value>;
calcLength(v, size, Var(inc)); // inc is a non-compile-time constant here, less possibilities of compiler optimization
我的问题是,是否有可能以某种方式保留原始接口(interface),并根据类型(编译时常量或不是)inc
?
calcLength(v, size, 1); // this should end up calcLength(v, size, Constant<1>());
calcLength(v, size, inc); // this should end up calcLength(v, size, Var(int));
注意:这是一个简单的例子。在我的实际问题中,我有几个函数,如calcLength
,而且它们很大,我不希望编译器内联它们。
注意 2:我也对不同的方法持开放态度。基本上,我想要一个解决方案来满足这些:
- 算法只指定一次(很可能在模板函数中)
- 如果我将
1
指定为inc
,则会实例化一个特殊函数,并且代码很可能会被矢量化 - 如果
inc
不是编译时常量,则调用一个通用函数 - 否则(非 1 编译时常量):调用哪个函数无关紧要
最佳答案
如果这里的目标只是优化,而不是在编译时上下文中使用,您可以向编译器提示您的意图:
static float calcLength_inner(const float *v, int size, int inc) {
float l = 0;
for (int i=0; i<size*inc; i += inc) {
l += v[i]*v[i];
}
return sqrt(l);
}
float calcLength(const float *v, int size, int inc) {
if (inc == 1) {
return calcLength_inner(v, size, inc); // compiler knows inc == 1 here, and will optimize
}
else {
return calcLength_inner(v, size, inc);
}
}
From godbolt ,您可以看到 calcLength_inner
已被实例化两次,有和没有常量传播。
这是一个 C 技巧(在 numpy 中广泛使用),但您可以编写一个简单的包装器以使其更易于在 C++ 中使用:
// give the compiler a hint that it can optimize `f` with knowledge of `cond`
template<typename Func>
auto optimize_for(bool cond, Func&& f) {
if (cond) {
return std::forward<Func>(f)();
}
else {
return std::forward<Func>(f)();
}
}
float calcLength(const float *v, int size, int inc) {
return optimize_for(inc == 1, [&]{
float l = 0;
for (int i=0; i<size*inc; i += inc) {
l += v[i]*v[i];
}
return sqrt(l);
});
}
关于c++ - 针对编译时常量优化的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55248789/