C ++数组作为模板参数

时间:2016-03-17 23:13:25

标签: c++ templates template-meta-programming compile-time

我想编写一个简单的多项式类,它可以获取系数数组并在编译时将其扩展为函数,因此我不需要在运行时循环遍历系数。我想做这样的事情:

template <PARAM_TYPE, PARAMS>
class P {
public:
    PARAM_TYPE eval(PARAM_TYPE p){
        //Does PARAMS[0] * pow(p, PARAMS.length() -1) + ... + PARAMS[N-1] 
    }
}

示例电话

P<double,{2,4,3}> quadratic;
quadratic.eval(5); //returns 73

我不想做循环,因为这需要时间。理想情况下,我希望能够在编译时形成上面的表达式。这可能吗?感谢

2 个答案:

答案 0 :(得分:1)

这是做你想做的事的一个例子。根据我注意到的用法以及你使用的编译器,编译器对于是否将所有代码优化为常量非常挑剔。

test here

#include <type_traits>

template<class T, unsigned Exponent>
inline constexpr typename std::enable_if<Exponent == 0, T>::type
pow2(const T base)
{
    return 1;
}

template<class T, unsigned Exponent>
inline constexpr typename std::enable_if<Exponent % 2 != 0, T>::type
pow2(const T base)
{
      return base * pow2<T, (Exponent-1)/2>(base) * pow2<T, (Exponent-1)/2>(base);
}

template<class T, unsigned Exponent>
inline constexpr typename std::enable_if<Exponent != 0 && Exponent % 2 == 0, T>::type
pow2(const T base)
{
    return pow2<T, Exponent / 2>(base) * pow2<T, Exponent / 2>(base);
}

template<typename ParamType>
inline constexpr ParamType polynomial(const ParamType&, const ParamType& c0)
{
  return c0;
}

template<typename ParamType, typename Coeff0, typename ...Coeffs>
inline constexpr ParamType polynomial(const ParamType& x, const Coeff0& c0, const Coeffs& ...cs)
{
    return (static_cast<ParamType>(c0) * pow2<ParamType, sizeof...(cs)>(x)) + polynomial(x, static_cast<ParamType>(cs)...);
}

unsigned run(unsigned x)
{
   return polynomial(x, 2, 4, 3);
}

double run(double x)
{
  return polynomial(x, 2, 4, 3);
}

unsigned const_unsigned()
{
    static const unsigned value = polynomial(5, 2, 4, 3);
    return value;
}

double const_double()
{
    static const double value = polynomial(5, 2, 4, 3);
    return value;
}

编辑:我已将代码更新为使用调整后的pow2<>()版本,该版本会在编译时积极执行计算。这个版本在-O2得到了很好的优化,实际上让我感到惊讶。您可以使用代码上方的按钮查看完整程序的生成程序集。如果所有参数都是常量,编译器将在编译时生成整个常量值。如果第一个参数依赖于运行时,它仍会为它生成非常严格的代码。

(感谢this question上的@dyp提供的灵感来源)

答案 1 :(得分:0)

为了评估多项式,一个好的算法是Horner(参见https://en.wikipedia.org/wiki/Horner%27s_method)。主要思想是递归计算多项式。设数为n的多项式P,系数为ai。很容易看出序列Pk = Pk-1 * x0 + an-k,P0 = a,P(x0)= Pn。

所以让我们使用constexpr函数实现这个算法:

template<class T>
constexpr double horner(double x, T an) { return an; }

template<class... T, class U = T>
constexpr double horner(double x, U an, T... a) { return horner(x, a...) * x + an; }

std::cout << horner(5., 1, 2, 1) << std::endl;

//test if the invocation of the constexpr function takes the constant expression branch
std::cout << noexcept(horner(5., 1, 2, 1)) << std::endl;

如您所见,使用递归公式实现使用constexpr函数对多项式进行求值非常容易。