微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

有没有办法在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;
 }

原文地址:https://www.jb51.cc/c/110755.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐