针对编译时常量优化的函数

gez*_*eza 5 c++ c++17 c++20

假设我有一个向量长度计算函数,它有一个附加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);
}
Run Code Online (Sandbox Code Playgroud)

现在,calcLength可以使用两种inc参数进行调用:何时inc在编译时已知,何时未知。我想要一个calcLength针对常见编译时值inc(如 1)的优化版本。

所以,我会有这样的东西:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,可以这样使用:

calcLength(v, size, Constant<1>()); // inc is a compile-time constant 1 here, calcLength can be vectorized
Run Code Online (Sandbox Code Playgroud)

或者

int inc = <some_value>;
calcLength(v, size, Var(inc)); // inc is a non-compile-time constant here, less possibilities of compiler optimization
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否有可能以某种方式保留原始界面,并根据类型(编译时常量与否)自动放入Constant/ ?Varinc

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));
Run Code Online (Sandbox Code Playgroud)

注意:这是一个简单的例子。在我的实际问题中,我有几个函数,例如calcLength,并且它们很大,我不希望编译器内联它们。


注2:我也对不同的方法持开放态度。基本上,我想要一个解决方案,它可以满足这些要求:

  • 该算法被指定一次(最有可能在模板函数中)
  • 如果我指定1as inc,则实例化一个特殊函数,并且代码很可能被矢量化
  • 如果inc不是编译时常量,则调用通用函数
  • 否则(非 1 编译时常量):调用哪个函数并不重要

Ant*_*ams 0

C++ 不提供检测提供的函数参数是否为常量表达式的方法,因此您无法自动区分提供的文字和运行时值。

如果参数必须是函数参数,并且您不愿意在这两种情况下更改它的调用方式,那么您这里唯一的杠杆就是参数的类型:您对Constant<1>()vs的建议Var(inc)非常好看待。