草庐IT

c++ - 有没有办法让这个 C++14 递归模板在 C++17 中更短?

coder 2024-02-01 原文

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, -2, 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, typename C_t, typename ... Cs_t>
constexpr auto poly_eval (X_t const & x, 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++14 中也可以使用逗号运算符(再次)的强大功能并初始化未使用的 C 风格整数数组来避免递归

template <typename X_t, typename C_t, typename ... Cs_t>
constexpr auto poly_eval (X_t const & x, 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;
 }

关于c++ - 有没有办法让这个 C++14 递归模板在 C++17 中更短?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47445850/

有关c++ - 有没有办法让这个 C++14 递归模板在 C++17 中更短?的更多相关文章

  1. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  2. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  5. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  6. 没有类的 Ruby 方法? - 2

    大家好!我想知道Ruby中未使用语法ClassName.method_name调用的方法是如何工作的。我头脑中的一些是puts、print、gets、chomp。可以在不使用点运算符的情况下调用这些方法。为什么是这样?他们来自哪里?我怎样才能看到这些方法的完整列表? 最佳答案 Kernel中的所有方法都可用于Object类的所有对象或从Object派生的任何类。您可以使用Kernel.instance_methods列出它们。 关于没有类的Ruby方法?,我们在StackOverflow

  7. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

    我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

  8. ruby-on-rails - 有没有办法为 CarrierWave/Fog 设置上传进度指示器? - 2

    我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r

  9. ruby - 没有类方法获取 Ruby 类名 - 2

    如何在Ruby中获取BasicObject实例的类名?例如,假设我有这个:classMyObjectSystem我怎样才能使这段代码成功?编辑:我发现Object的实例方法class被定义为returnrb_class_real(CLASS_OF(obj));。有什么方法可以从Ruby中使用它? 最佳答案 我花了一些时间研究irb并想出了这个:classBasicObjectdefclassklass=class这将为任何从BasicObject继承的对象提供一个#class您可以调用的方法。编辑评论中要求的进一步解释:假设你有对象

  10. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

随机推荐