c++ комбинира стойности от два (или повече) пакета с параметри

Как е възможно да се комбинират стойности от два пакета параметри в C++? С други думи, как се пише функция

LetsStart<int, -1, 10, 3>("This is -1", "And this is 10", "3!!!");

което би извело

-1 This is -1                                                                                                                                   
10 And this is 10                                                                                                                               
3 3!!! 

Т.е. трябва да избере 1-ва стойност от първия пакет и 1-ва стойност от втория пакет, след това 2-ра стойност от двата пакета, след това 3-та стойност от двата пакета и така нататък...

В първите си опити опитах нещо подобно

template<class T, T... Firsts, class TSecond>
void LetsStart(TSecond... Seconds) {
   Output((Firsts, Seconds)...);
}

но това не проработи...

// Разбира се, че написах тази функция, но вярвам, че съществува по-правилен и прост начин за изпълнение на тази задача. И така, бихте ли ми посочили пътя?


person Void    schedule 27.09.2014    source източник
comment
Идеята е да съхранявате всеки пакет в кортеж (или друг клас) и след това да обхождате тези два кортежа чрез индекс N, който преминава от 0 до sizeof ... (Firsts). Бих започнал да отговарям, ако не смятам получения клас за малко безполезен ... какво имате предвид с това?   -  person davidhigh    schedule 28.09.2014
comment
Наистина не разбирам изискването, но защо не можете просто да използвате карта?   -  person Zaid Amir    schedule 28.09.2014
comment
Вие сте на прав път; просто не можете да разширите пакети с параметри в този контекст. Един контекст, в който е разрешено разширяване, е braced-init-list: coliru.stacked-crooked.com/ a/0c4980989603a770   -  person dyp    schedule 28.09.2014


Отговори (2)


В C++11 можете да използвате следната функция:

template<typename T, T... V, typename F, typename... A>
void f(F &&f, A&&... args) {
    static_assert(sizeof...(V) == sizeof...(A), "Argument lists size mismatch");
    int arr[] = { 0, (std::forward<F>(f)(V, std::forward<A>(args)), 0)... };
    (void)arr;
}

Той приема два списъка с параметри, както е поискано, и допълнителна функция F, след което разопакова параметрите и предава N-тия от всеки списък към дадената функция.
Трябва да работи и в случай, че не са предоставени параметри.

В C++17 можете да го пренапишете, както следва:

template<typename T, T... V, typename F, typename... A>
void f(F &&f, A&&... args) {
    static_assert(sizeof...(V) == sizeof...(A));
    (std::forward<F>(f)(V, std::forward<A>(args)), ...);
}

И в двата случая съм проверил дали двата списъка са с еднакъв размер, тъй като не беше уточнено какво да правя в такъв случай.

Можете да тествате двете функции с примера main по-долу:

#include<utility>
#include<iostream>

// ...

int main() {
    auto l = [](auto v, auto s) { std::cout << v << " " << s << std::endl; };
    f<int, -1, 10, 3>(l, "This is -1", "And this is 10", "3!!!");
}
person skypjack    schedule 09.09.2016
comment
Защо се изисква пренасочване при обаждане до f (std::forward<F>(f)(/*...*/))? - person Innokentiy Alaytsev; 05.02.2019
comment
@InnokentiyAlaytsev да спазва референтните квалификатори на оператора за извикване на функция, ако има такива. - person skypjack; 05.02.2019

C++11 версия:

CE: https://gcc.godbolt.org/z/xIUL1J

#include<iostream>

template<class... T>
void LetsStart(){}

template<class T, class U>
void print(T t, U u)
{
    std::cout << t << " " << u << '\n';
}

template<class T, T f,  T... ts, class A, class... Arg>
void LetsStart(A&& a, Arg&&... args){
    print(f, a);
    LetsStart<T, ts...>(args...);
}

void foo() {
    LetsStart<int, -1, 10, 3>("This is -1", "And this is 10", "3!!!");
}
person balki    schedule 05.02.2019
comment
Версията C++11, предоставена от @skypjack, има важно предимство пред вашата реализация - не е рекурсивна. В края на дните всъщност няма значение, защото компилаторът ще вгради всичко. Но ако някой иска да създаде компилация за отстраняване на грешки, нерекурсивната версия води до много по-малко асемблиране и междинни функции. - person Innokentiy Alaytsev; 05.02.2019