【问题标题】:unpacking values of an array as parameters to a variadic function将数组的值解包为可变参数函数的参数
【发布时间】:2019-04-26 15:45:17
【问题描述】:

我正在尝试(在编译时)将整数解包为可变参数函数的参数。这个想法是在编译时将这些值打包在一个数组或std::index_sequence (c++14) 中。我尝试使用旧帖子中的一些答案,但我发现示例代码不适合我的级别。

这是一个简单的示例,其中包含我需要在我正在编写的代码中实现的功能,在本例中尝试使用std::make_index_sequence。我不一定需要使用后者。问题是序列的值没有被解包为可变参数函数的参数:

#include <cstdio>
#include <iostream>
#include <utility>

using namespace std;


void print(const int &val){
  cout << val << endl;
}

template<typename ...S> void print(const int &val, const S&... others)
{
  print(val);
  print(others...);
}

template<size_t n> void printNumbers(){
  std::make_index_sequence<n> a;
  print(a);
}


int main(){
  printNumbers<6>();
}

GCC8 的输出:

    tet.cc: In instantiation of ‘void printNumbers() [with long unsigned int n = 6]’:
tet.cc:25:19:   required from here
tet.cc:20:8: error: no matching function for call to ‘print(std::make_index_sequence<6>&)’
   print(a);
   ~~~~~^~~
tet.cc:8:6: note: candidate: ‘void print(const int&)’
    void print(const int &val){
     ^~~~~
tet.cc:8:6: note:   no known conversion for argument 1 from ‘std::make_index_sequence<6>’ {aka ‘std::integer_sequence<long unsigned int, 0, 1, 2, 3, 4, 5>’} to ‘const int&’
tet.cc:12:30: note: candidate: ‘template<class ... S> void print(const int&, const S& ...)’
template<typename ...S> void print(const int &val, const S&... others)
                                 ^~~~~
tet.cc:12:30: note:   template argument deduction/substitution failed:
tet.cc:20:9: note:   cannot convert ‘a’ (type ‘std::make_index_sequence<6>’ {aka ‘std::integer_sequence<long unsigned int, 0, 1, 2, 3, 4, 5>’}) to type ‘const int&’

【问题讨论】:

    标签: c++ c++11 c++14 variadic-templates template-meta-programming


    【解决方案1】:

    std::make_index_sequence&lt;6&gt; 是以下的别名:

    std::integer_sequence<std::size_t, 0, 1, 2, 3, 4, 5>
    

    这是表达式a 的类型,它是函数调用print(a) 的参数。您的 print 函数需要单独的值,而不是 std::integer_sequence

    为了使您的实现工作,您应该首先推断索引,然后才将它们用作print 的参数:

    template <std::size_t... Is>
    void printNumbers(std::index_sequence<Is...>)
    {
        print(Is...);
    }
    
    template <std::size_t N>
    void printNumbers()
    {
        printNumbers(std::make_index_sequence<N>{});
    }
    

    中,您可以删除中间的 print 函数,然后说:

    template <std::size_t... Is>
    void printNumbers(std::index_sequence<Is...>)
    {
        (print(Is), ...);
    }
    

    中,您既可以创建索引序列,也可以在单个函数中推断其索引:

    template <std::size_t N>
    void printNumbers()
    {
        [] <std::size_t... Is> (std::index_sequence<Is...>)
        { (print(Is), ...); }(std::make_index_sequence<N>{});
    }
    

    DEMO

    【讨论】:

      【解决方案2】:

      作为 Piotr Skotnicki 答案的附录,我提出了一种 C++14 方法来避免递归 print()

      不像 C++17 解决方案那样优雅,基于模板折叠,但同样允许避免使用递归(并且考虑到模板递归通常受到编译器的严格限制,因此递归解决方案有效但在 @ 987654322@超出递归限制)。

      您必须像往常一样编写printNumber() 函数,将std::make_index_sequence&lt;N&gt;(继承自std::index_sequence&lt;0, 1, ...., N-1&gt; 又名std::integer_sequence&lt;std::size_t, 0, 1, ..., N-1&gt;)传递给另一个函数

      template <std::size_t N>
      void printNumbers ()
       { printNumbers2(std::make_index_sequence<N>{}); }
      

      但在printNumbers2() 中,您可以避免调用递归的print(),并且您可以调用print(),在未使用的数组的初始化中有效地调用std::cout

      template <std::size_t ... Is>
      void printNumbers2 (std::index_sequence<Is...>)
       {
         using unused = int[];
      
         (void)unused { 0, (print(Is), 0)... };
       } 
      

      您也可以避免在printNumbers2() 中直接打印两个print() 函数

      void printNumbers2 (std::index_sequence<Is...>)
       {
         using unused = int[];
      
         (void)unused { 0, (std::cout << val << std::endl, 0)... };
       } 
      

      您可以在 C++17/C++20 模板折叠解决方案中执行相同操作。

      在 C++11 中,此解决方案不起作用,只是因为 std::make_integer_sequencestd::index_sequence 是从 C++11 引入的。

      如果您为 std::make_integer_sequencestd::index_sequence 编写 C++11 代理,您也可以将此解决方案改编为 C++11。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-10-02
        • 1970-01-01
        • 1970-01-01
        • 2020-10-25
        • 1970-01-01
        • 1970-01-01
        • 2015-09-22
        相关资源
        最近更新 更多