читать аргументы из шаблона variadic - PullRequest
7 голосов
/ 06 сентября 2010

Меня немного смущает, как я могу прочитать каждый аргумент из кортежа с помощью шаблонов с переменными числами.

Рассмотрим эту функцию:

template<class...A> int func(A...args){
int size = sizeof...(A);
.... }

Я вызываю ее из основного файла как:

func(1,10,100,1000);

Теперь я не знаю, как мне расширить тело func, чтобы иметь возможность читать каждый аргумент отдельно, чтобы я мог, например, сохранить аргументы в массиве.

Ответы [ 4 ]

12 голосов
/ 06 сентября 2010

Вы должны предоставить переопределения для функций для использования первых N (обычно одного) аргументов.

void foo() {
   // end condition argument pack is empty
}

template <class First, class... Rest> 
void foo(First first, Rest... rest) {
    // Do something with first
    cout << first << endl; 

    foo(rest...); // Unpack the arguments for further treatment
}

Когда вы распаковываете параметр переменной, он находит следующую перегрузку.

Пример:

foo(42, true, 'a', "hello");
// Calls foo with First = int, and Rest = { bool, char, char* }
// foo(42, Rest = {true, 'a', "hello"}); // not the real syntax

Затем на следующем уровне мы расширяем предыдущий Rest и получаем:

foo(true, Rest = { 'a', "hello"}); // First = bool

И так до тех пор, пока Rest не содержит членов, в этом случае распаковка вызывает foo() (перегрузка без аргументов).


Хранение упаковки, если разные типы

Если вы хотите сохранить весь пакет аргументов, вы можете использовать std::tuple

template <class... Pack>
void store_pack(Pack... p) {
    std::tuple<Pack...> store( p... );
    // do something with store
}

Однако это кажется менее полезным.

Хранение упаковки, если она однородна

Если все значения в пакете имеют одинаковый тип, вы можете сохранить их все так:

vector<int> reverse(int i) {
    vector<int> ret;
    ret.push_back(i);
    return ret;
}

template <class... R>
vector<int> reverse(int i, R... r) {
    vector<int> ret = reverse(r...);
    ret.push_back(i);
    return ret; 
}

int main() {
    auto v = reverse(1, 2, 3, 4);
    for_each(v.cbegin(), v.cend(), 
        [](int i ) { 
            std::cout << i << std::endl; 
        }
    );
}

Однако это кажется еще менее полезным.

3 голосов
/ 06 сентября 2010

Если все аргументы одного типа, вы можете сохранить аргументы в массиве следующим образом (используя тип первого аргумента для массива):

template <class T, class ...Args>
void foo(const T& first, const Args&... args)
{
    T arr[sizeof...(args) + 1] = { first, args...};
}

int main()
{
    foo(1);
    foo(1, 10, 100, 1000);
}

Если типы разныеЯ полагаю, вы могли бы использовать boost::any, но тогда я не понимаю, как вы собираетесь выяснить за пределами данного шаблона, какой элемент какого типа (как вы собираетесь использовать сохраненные значения).


Редактировать: Если все аргументы одного типа и вы хотите сохранить их в контейнере STL, вы можете использовать std::initializer_list<T>.Например, пример Motti для хранения значений в обратном порядке:

#include <vector>
#include <iostream>
#include <iterator>

template <class Iter>
std::reverse_iterator<Iter> make_reverse_iterator(Iter it)
{
    return std::reverse_iterator<Iter>(it);
}

template <class T>
std::vector<T> reverse(std::initializer_list<T> const & init)
{

    return std::vector<T>(make_reverse_iterator(init.end()), make_reverse_iterator(init.begin()));
}

int main() {
    auto v = reverse({1, 2, 3, 4});
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << std::endl;
    }
} 
2 голосов
/ 30 сентября 2010

Для вставки в массив, если аргументы имеют разные типы, вы также можете использовать std::common_type<>

template<class ...A> void func(A ...args){
   typedef typename std::common_type<A...>::type common;
   std::array<common, sizeof...(A)> a = {{ args... }};
}

Так, например, func(std::string("Hello"), "folks") создает массив std::string.

1 голос
/ 06 сентября 2010

Если вам нужно сохранить аргументы в массиве, вы можете использовать массив boost::any следующим образом:

template<typename... A> int func(const A&... args)
{
  boost::any arr[sizeof...(A)] = { args... };
  return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...