有没有办法在C 17中使这个C 14递归模板更短?
该poly_eval函数将计算在特定x值处评估具有特定系数集的多项式的结果.例如,poly_eval(5,1,-2,-1)计算x ^ 2 – 2x – 1,x = 5.这都是constexpr所以如果给它常量,它将在编译时计算答案.
它目前使用递归模板在编译时构建多项式求值表达式,并依赖于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 ….对于大多数合理的类型,它们应该是等价的,并且可以很容易地修改答案以扩展到我的递归扩展到的内容. 我选择了第一个答案,因为它是第一个,它的简洁性更符合我原始问题的精神.但是,如果我要选择一个版本进行制作,我会选择第二个版本. 解决方法
使用逗号运算符的功能(显然是C 17折叠),我想你可以写如下poly_eval()
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; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |