【问题标题】:How to get arguments from Variadics Template如何从可变参数模板中获取参数
【发布时间】:2021-10-29 08:17:31
【问题描述】:

This 已经是一个很好的答案,但是,当我尝试对作为 typename 的参数(不知道确切的词)执行相同操作时,它们传递了任意数量的参数作为参数,例如:

int sum=0;
int func()
{
    return sum;
}

template <int first, int ... rest>
int func()
{
    sum += first;
    return func(rest...); //Error   C2660   'func': function does not take 4 arguments
    /*
     return func<rest...>(); this also doesn't work: Error 'int func(void)': could not deduce template argument for 'first' and 'func': no matching overloaded function found
     */
}


int main()
{
    cout << func<1,2,3,4,5>();
}

为什么会出现错误?有没有可能的修复?另外,我需要将参数作为类型名而不是参数传递。

【问题讨论】:

    标签: c++ recursion variadic-templates variadic-functions template-meta-programming


    【解决方案1】:

    首先,“基础”函数需要是模板。

    那么为了区分这两个模板,parameter-pack 模板需要至少接受两个模板参数。

    最后,您可以在不使用全局 sum 变量的情况下解决此问题,但使用 return 语句中的加法。

    把它们放在一起:

    template <int first>
    int func()
    {
        return first;
    }
    
    template <int first, int second, int ...rest>
    int func()
    {
        return first + func<second, rest...>();
    }
    

    【讨论】:

      【解决方案2】:

      如果您想返回参数包的总和,并且可以使用稍微不同的语法,则可以使用 C++17 以后的折叠表达式或使用 'if constexpr' 构建递归

      template<typename... args_t>
      static constexpr auto sum(args_t&&... values)
      {
          return (values + ...);
      }
      
      // the sum is evaluated at compile time
      static_assert(sum(1, 2, 3, 4) == 10ul);
      
      // or like this without fold
          template<int value, int... values>
      constexpr int sum2()
      {
          if constexpr (sizeof...(values) > 0)
          {
              return value + sum2<values...>();
          }
          else
          {
              return value;
          }
      };
      
      static_assert(sum2<1,2,3,4>() == 10);
      

      【讨论】:

      • 谢谢,但我这样做只是为了说明,因为我的真实代码有很多外部函数和变量
      • 不客气,这只是为了向您指出 C++17 工具箱中的一些新工具 :)
      【解决方案3】:

      对于作为值总和的简单用例,有很多方法(如在一些程序员老兄和 P Kramer 的回答中)。

      我将向您展示递归解决方案的一个变体(一些程序员老兄的回答),它在这种情况下并不是特别有用,但在其他情况下可能会很有用(当基本函数使某些东西一致并等于时避免代码重复递归版本):而不是接收和管理最后一个值的基本版本,接收默认类型并且什么都不做的基本版本(在总和情况下返回零):

      template <typename = void>
      int func ()
       { return 0; }
      

      所以你可以编写递归版本如下,没有second

      template <int first, int ... rest>
      int func ()
       { return first + func<rest...>(); }
      

      诀窍在于递归调用:func&lt;rest...&gt;()

      ...rest 模板包不为空时,递归调用func&lt;rest...&gt;() 调用递归func()

      但是当...rest模板包为空时,递归调用func&lt;rest...&gt;()变成func&lt;&gt;()不匹配递归func()(至少需要一个模板整数值)但匹配(感谢默认void类型)func&lt;void&gt;(),所以接地func()函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-08
        • 1970-01-01
        • 2016-12-01
        • 2014-03-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多