распаковка значений массива как параметров в переменную функцию - PullRequest
0 голосов
/ 24 ноября 2018

Я пытаюсь (во время компиляции) распаковать целые числа в качестве аргументов для переменной функции.Идея заключалась бы в том, чтобы эти значения были упакованы в массив или в 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&’

Ответы [ 2 ]

0 голосов
/ 24 ноября 2018

В качестве дополнения к ответу Петра Скотницкого я предлагаю C ++ 14 способ избежать рекурсивного print().

Не так элегантно, как решение C ++ 17, основанное на свертывании шаблонов, но в равной степени позволяет избежать использования рекурсии (и учтите, что рекурсия шаблона обычно строго ограничена компиляторами, поэтому рекурсивное решение работает, ноне когда N превышает предел рекурсии).

Вы должны написать функцию printNumber() как обычно, передав std::make_index_sequence<N> (которая наследуется от std::index_sequence<0, 1, ...., N-1> aka std::integer_sequence<std::size_t, 0, 1, ..., N-1>) другой функции

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)... };
 } 

Вы также можете избежать печати обеих функций print() непосредственно в printNumbers2()

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_sequence и std::index_sequence введены из C ++ 11.

Если вы пишете суррогат C ++ 11для std::make_integer_sequence и std::index_sequence вы можете адаптировать это решение также к C ++ 11.

0 голосов
/ 24 ноября 2018

std::make_index_sequence<6> является псевдонимом для:

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), ...);
}

В youможет создавать последовательность индексов и выводить ее индексы в пределах одной функции:

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

DEMO

...