用于使用 Horner 方法进行多项式计算的 C++ constexpr

标签 c++ templates instantiation

我希望能够使用 Horner 方法计算多项式的导数并将结果用作 constexpr .这看起来非常平凡,但我遗漏了一些明显的东西,因为编译器说我超出了最大递归深度。核心递归发生在这里:

template<size_t d, size_t i, typename C, typename X>
constexpr X evalImpl(const C &c, const X &x) {
    return i >= (C::SizeAtCompileTime - 1 - d) ? 1 : evalImpl<d, i + 1, C, X>(c, x);
}

你甚至不需要知道 Horner 的方法就知道这里发生了什么,所以我尽可能地剥离了代码,甚至删除了如何 x使用,因为它似乎与我遇到的问题无关。

想法是当一个索引i等于多项式的次数 Degree<C>::value减去导数的阶数 d ,那么递归应该停止。否则,它应该增加索引 i然后重试。

我用以下形式调用上面的递归

 eval<derivative, 0>(c, x)

哪里cEigen::Matrix<double,1,7> 类型的特征矩阵, 和 x是一个双。这个想法是从 0 开始计算到多项式的次数。

编译器错误信息的形式是

In file included from /mnt/c/proj/src/main.cpp:11:0:
/mnt/c/proj/src/polynomial.h: In instantiation of 'constexpr X {anonymous}::evalImpl(const C&, const X&) [with long unsigned int d = 1ul; long unsigned int i = 898ul; C = Eigen::Matrix<double, 1, 7>; X = double]':
/mnt/c/proj/src/polynomial.h:74:108:   recursively required from 'constexpr X {anonymous}::evalImpl(const C&, const X&) [with long unsigned int d = 1ul; long unsigned int i = 1ul; C = Eigen::Matrix<double, 1, 7>; X = double]'
/mnt/c/proj/src/polynomial.h:74:108:   required from 'constexpr X {anonymous}::evalImpl(const C&, const X&) [with long unsigned int d = 1ul; long unsigned int i = 0ul; C = Eigen::Matrix<double, 1, 7>; X = double]'
/mnt/c/proj/src/polynomial.h:109:39:   required from 'constexpr X Polynomial::eval(const C&, const X&) [with long unsigned int d = 1ul; C = Eigen::Matrix<double, 1, 7>; X = double]'
/mnt/c/proj/src/main.cpp:306:66:   required from here
/mnt/c/proj/src/polynomial.h:74:108: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
         return i >= (C::SizeAtCompileTime - 1 - d) ? 1 : evalImpl<d, i + 1, C, X>(c, x);

最佳答案

这里的条件:

return i >= (C::SizeAtCompileTime - 1 - d) ? 1 : evalImpl<d, i + 1, C, X>(c, x);

不是if constexpr。因此无论i >= (C::SizeAtCompileTime - 1 - d)true还是false,剩下的总是会被实例化.因此递归不会如你所愿地停止。

更改为:

if constexpr (i >= (C::SizeAtCompileTime - 1 - d)) {
    return 1;
} else { 
    return evalImpl<d, i + 1, C, X>(c, x);  
}

编辑:

如果您无法访问 C++17,请使用标签分派(dispatch):

template<size_t d, size_t i, typename C, typename X>
constexpr X evalImpl_impl(const C &c, const X &x, std::true_type) {
    return 1;
}

template<size_t d, size_t i, typename C, typename X>
constexpr X evalImpl_impl(const C &c, const X &x, std::false_type) {
    return evalImpl_impl<d, i + 1, C, X>(c, x, std::integral_constant<bool, C::SizeAtCompileTime-1-d <= i+1>{});
}

template<size_t d, size_t i, typename C, typename X>
constexpr X evalImpl(const C &c, const X &x) {
    return evalImpl_impl(c, x, std::integral_constant<bool, C::SizeAtCompileTime-1-d <= i>{});
}

关于用于使用 Horner 方法进行多项式计算的 C++ constexpr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50232832/

相关文章:

c++ - 我如何才能始终强制包含标题?

c++ - 导出模板将如何实现?

java - 我在用 Java 从磁盘加载对象时遇到问题

java - 有没有办法在 Java 中按名称实例化一个类?

c++ - 重载、字符串和默认参数

c++ - 从 IAudioClient::GetMixFormat 解释 WAVEFORMATEXTENSIBLE

c++ - 在编译时用基于模板的长度初始化一个 const 数组

java - 抽象类 NumberFormat - 对 getInstance() 非常困惑

c++ - 为什么我的 pow 方法不起作用?

c++ - 模板赋值运算符 : valid C++?