С++ 20 представлений с пакетом параметров или списком инициализаторов

Я хочу передать функции переменное количество аргументов, а затем получить представление о них. Мне нужно применить несколько функций к каждому из них. Я пытался заставить это работать как с пакетами параметров, так и со списками инициализаторов. Почему эти решения не работают и есть ли способ это сделать?

В идеале конечная функция будет выглядеть так:

template <typename some_way_of_taking_multiple_arguments>
void foo(some_way_of_taking_multiple_arguments bar) {
  using namespace std::views;
  auto data = bar | transform(func1) | transform(func2);
  other_func();
  data | transform(func3);
}

Когда я пытаюсь вызвать функцию следующим образом: foo({arg1, arg2, arg3}), она не может определить тип шаблона.


person Edward    schedule 07.09.2020    source источник
comment
Вы должны добавить версии, которые вы пробовали, и ошибки, которые вы получаете для каждой из них.   -  person cigien    schedule 07.09.2020
comment
Это проприетарный код, поэтому он может делиться только шаблоном, не вдаваясь в определения типов и тому подобное.   -  person Edward    schedule 07.09.2020
comment
Я уверен, что вы можете сделать минимально воспроизводимый пример всего с парой строк, демонстрирующих проблему. Кроме того, SO не одобряет просьбы о помощи с проприетарным кодом.   -  person cigien    schedule 07.09.2020
comment
Теперь я уверен, что причина, по которой это не сработало, заключается в том, что функция func 3 имела возвращаемый тип void. Это показано здесь: godbolt.org/z/8zara4   -  person Edward    schedule 07.09.2020
comment
@cigien Где это осуждается? Неодобрительно, если вы не предоставите достаточно информации для ответа, что может помешать, если у вас есть проприетарный код; это просто означает больше работы для ОП.   -  person Yakk - Adam Nevraumont    schedule 08.09.2020
comment
@Yakk-AdamNevraumont Достаточно честно, я не знаю, осуждается ли это, меня это просто раздражает :( Думаю, я должен удалить эту часть комментария, но я хочу сохранить часть о MRE.   -  person cigien    schedule 08.09.2020


Ответы (3)


Пока все аргументы одного типа, вы можете создать initializer_list следующим образом:

void foo(auto ... bar_args) 
{
  using namespace std::views;

  std::initializer_list bar{bar_args...};  // uses CTAD to deduce type

  auto data = bar | transform(func1) | transform(func2);
  data | transform(func3);
}

и вызывать его так:

int main()
{
  int a=1, b=2, c=3, d=4;
  foo(a,b,c,d); 
}

Вот демонстрация.

person cigien    schedule 07.09.2020
comment
Я думаю, использование std::array должно быть лучше, не так ли? - person Antoine Morrier; 08.09.2020
comment
@AntoineMorrier На самом деле array будет копировать базовые элементы, тогда как initializer_list более легкий и ближе к view. Массив тоже подойдет. - person cigien; 08.09.2020
comment
Я не знал, что initializer_list более легкий. Спасибо ! - person Antoine Morrier; 08.09.2020

template<class T, std::size_t N>
void foo( T const(& arg)[N] ) {
  for( auto x : arg )
    std::cout << x;
}

Это можно назвать так:

foo( {1,2,3} );

массив работает с c++20 нормально просматривается.

person Yakk - Adam Nevraumont    schedule 08.09.2020

Один из способов, который я нашел для этого, — установить тип параметра на std::initializer_list, а затем изменить строку:

data | transform(func3); to: for (const auto &datum: data) {func3(datum);}

Это связано с тем, что возвращаемый тип func3 недействителен, вы можете использовать std::views::transform только с функциями, которые что-то возвращают.

Демонстрация здесь

person Edward    schedule 07.09.2020