它目前使用递归模板在编译时构建多项式求值表达式,并依赖于C 14为constexpr.我想知道是否有人能想出一个很好的方法来删除递归模板,可能使用C 17.执行模板的代码使用clang和gcc中的__uint128_t类型.
#include <type_traits> #include <tuple> template <typename X_t,typename Coeff_1_T> constexpr auto poly_eval_accum(const X_t &x,const Coeff_1_T &c1) { return ::std::pair<X_t,Coeff_1_T>(x,c1); } template <typename X_t,typename Coeff_1_T,typename... Coeff_TList> constexpr auto poly_eval_accum(const X_t &x,const Coeff_1_T &c1,const Coeff_TList &... coeffs) { const auto &tmp_result = poly_eval_accum(x,coeffs...); auto saved = tmp_result.second + tmp_result.first * c1; return ::std::pair<X_t,decltype(saved)>(tmp_result.first * x,saved); } template <typename X_t,typename... Coeff_TList> constexpr auto poly_eval(const X_t &x,const Coeff_TList &... coeffs) { static_assert(sizeof...(coeffs) > 0,"Must have at least one coefficient."); return poly_eval_accum(x,coeffs...).second; } // This is just a test function to exercise the template. __uint128_t multiply_lots(__uint128_t num,__uint128_t n2) { const __uint128_t cf = 5; return poly_eval(cf,num,n2,10); } // This is just a test function to exercise the template to make sure // it computes the result at compile time. __uint128_t eval_const() { return poly_eval(5,1); }
另外,我在这里做错了吗?
——–对答案的评论——–
下面有两个很好的答案.一个是clear and terse,but may not handle certain situations involving complex types (expression trees,matrices,etc..) well,虽然它做得很好.它还依赖于有些模糊的运算符.
另一个是不那么简洁,但仍然是much clearer than my original recursive template,and it handles types just as well.它扩展为’cn x *(cn-1 x *(cn-2 …’,而我的递归版本扩展为cn x * cn-1 x * x * cn -2 ….对于大多数合理的类型,它们应该是等价的,并且可以很容易地修改答案以扩展到我的递归扩展到的内容.
我选择了第一个答案,因为它是第一个,它的简洁性更符合我原始问题的精神.但是,如果我要选择一个版本进行制作,我会选择第二个版本.
解决方法
template <typename X_t,typename C_t,typename ... Cs_t> constexpr auto poly_eval (X_t const & x,C_t a,Cs_t const & ... cs) { ( (a *= x,a += cs),...,(void)0 ); return a; }
扔掉poly_eval_accum().
观察第一个系数是否已解释,因此您也可以删除static_assert()并通过复制传递,并成为累加器.
– 编辑 –
添加了一个替代版本来解决返回类型的问题,使用std :: common_type表达式的decltype(),如OP建议的那样;在这个版本中,a再次是一个常量引用.
template <typename X_t,C_t const & c1,Cs_t const & ... cs) { decltype(((x * c1) + ... + (x * cs))) ret { c1 }; ( (ret *= x,ret += cs),(void)0 ); return ret; }
– 编辑2 –
额外答案:使用逗号运算符(再次)的功能并初始化未使用的C样式整数数组,也可以避免C14中的递归
template <typename X_t,C_t const & a,Cs_t const & ... cs) { using unused = int[]; std::common_type_t<decltype(x * a),decltype(x * cs)...> ret { a }; (void)unused { 0,(ret *= x,ret += cs)... }; return ret; }