Подтвердить что ты не робот

Вставка вариационного списка аргументов в вектор?

Простите меня, если на это уже был дан ответ, поскольку я не смог его найти...

В принципе у меня есть объект, который должен взять в него переменный список аргументов и сохранить аргументы в векторе. Как инициализировать вектор из аргументов вариационного конструктора?

class GenericNode {
public:
    GenericNode(GenericNode*... inputs) {
            /* Something like... */
        // inputs_.push_back(inputs)...;
}
private:
    std::vector<GenericNode*> inputs_;
};
4b9b3361

Ответ 1

Лучше всего использовать список инициализаторов

#include <initializer_list>
#include <vector>
class GenericNode {
public:
    GenericNode(std::initializer_list<GenericNode*> inputs) 
        :inputs_(inputs) {} //well that easy
private:
    std::vector<GenericNode*> inputs_;
};
int main() {
    GenericNode* ptr;
    GenericNode node{ptr, ptr, ptr, ptr};
} //compilation at http://stacked-crooked.com/view?id=88ebac6a4490915fc4bc608765ba2b6c

Ближе всего к тому, что у вас уже есть, с использованием С++ 11 следует использовать вектор initializer_list:

    template<class ...Ts>
    GenericNode(Ts... inputs) 
        :inputs_{inputs...} {} //well that easy too
    //compilation at http://stacked-crooked.com/view?id=2f7514b33401c51d33677bbff358f8ae

И здесь версия С++ 11 без инициализатора. Это уродливое, сложное и требует от многих компиляторов функций. Используйте список инициализаций

template<class T>
using Alias = T;

class GenericNode {
public:
    template<class ...Ts>
    GenericNode(Ts... inputs) { //SFINAE might be appropriate
         using ptr = GenericNode*;
         Alias<char[]>{( //first part of magic unpacker
             inputs_.push_back(ptr(inputs))
             ,'0')...,'0'}; //second part of magic unpacker
    }
private:
    std::vector<GenericNode*> inputs_;
};
int main() {
    GenericNode* ptr;
    GenericNode node(ptr, ptr, ptr, ptr);
} //compilation at http://stacked-crooked.com/view?id=57c533692166fb222adf5f837891e1f9
//thanks to R. Martinho Fernandes for helping me get it to compile

Не связанный со всем, я не знаю, владеют ли они указателями или нет. Если они есть, используйте std::unique_ptr.

Ответ 2

    // inputs_.push_back(inputs)...;

Это не работает, потому что вы не можете развернуть пакет параметров как оператор, только в определенных контекстах, таких как список аргументов функции или список инициализаторов.

Также ваша подпись конструктора неверна, если вы пытаетесь написать вариационный шаблон, он должен быть шаблоном!

Как только вы правильно пишете подпись конструктора, ответ прост, просто создайте вектор с расширением пакета:

#include <vector>

class GenericNode
{
public:
  template<typename... T>
    GenericNode(T*... inputs) : inputs_{ inputs... }
    { }
private:
    std::vector<GenericNode*> inputs_;
};

(Вместо этого вы можете установить его в тело конструктора с помощью:

inputs_ = { inputs... };

но классные дети используют инициализаторы членов, не назначаемые в корпусе конструктора.)

Недостатком этого решения является то, что конструктор шаблонов принимает любые аргументы указателя, но затем выдаст ошибку при попытке построить вектор, если аргументы не будут конвертированы в GenericNode*. Вы можете ограничить шаблон только принятием указателей GenericNode, но это произойдет автоматически, если вы сделаете то, что предложите другие ответы, и сделайте конструктор std::initializer_list<GenericNode*>, а затем вам не нужны уродливые трюки enable_if SFINAE.

Ответ 3

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

class GenericNode {
public:
    GenericNode(std::initializer_list<GenericNode*> inputs) : inputs_(inputs)
    {
    }
private:
    std::vector<GenericNode*> inputs_;
};

template <class ... T>
GenericNode* foo(T ... t)
{
    return new GenericNode({t...});
}

Ответ 4

Другой способ сделать это:

#include <iostream>
#include <vector>

using std::vector;

template <typename T>
void variadic_vector_emplace(vector<T>&) {}

template <typename T, typename First, typename... Args>
void variadic_vector_emplace(vector<T>& v, First&& first, Args&&... args)
{
    v.emplace_back(std::forward<First>(first));
    variadic_vector_emplace(v, std::forward<Args>(args)...);
}

struct my_struct
{
    template <typename... Args>
    my_struct(Args&&... args)
    {
        variadic_vector_emplace(_data, std::forward<Args>(args)...);
    }

    vector<int>& data() { return _data; }

private:
  vector<int> _data;
};


int main()
{
    my_struct my(5, 6, 7, 8);

    for(int i : my.data())
      std::cout << i << std::endl;
}

Ответ 5

class Blob
 {
    std::vector<std::string> _v;
 public:

    template<typename... Args>
    Blob(Args&&... args)
    : _v(std::forward<Args>(args)...)
    {  }

};

int main(void)
{
    const char * shapes[3] = { "Circle", "Triangle", "Square" };

    Blob b1(5, "C++ Truths"); 
    Blob b2(shapes, shapes+3);
}

Пример из С++ 11 Истины выглядят достаточно просто...;) Не полное решение, но может дать вам некоторые идеи.