2012-12-20 24 views
22

原谅我,如果这已被回答,因为我找不到它...将可变参数列表插入向量中?

基本上我有一个对象,需要在它的构造函数中使用可变参数列表并将参数存储在向量中。我如何从一个可变参数构造函数的参数初始化一个向量?

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

你的例子中有一些无效的语法。你想问什么? –

+8

使用'std :: initializer_list '。 –

+0

对不起。为了澄清,我该如何使用参数列表填充std :: vector? @MooingDuck,我会看看std :: initializer_list。谢谢。 – fredbaba

回答

22

最好的事情是将使用初始化列表

#include <initializer_list> 
#include <vector> 
class GenericNode { 
public: 
    GenericNode(std::initializer_list<GenericNode*> inputs) 
     :inputs_(inputs) {} //well that's 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 

的最接近于你已经拥有,使用C++ 11是使用向量的initializer_list:

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

这里是一个没有initializer_lists的C++ 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

+0

不会'template GenericNode(T * ... inputs):inputs_ {inputs ...} {}'更接近他已经有?尽管如此,我仍然会使用'std :: initializer_list '。 –

+0

@JonathanWakely:不知道为什么我从来没有想到这一点。固定。 –

+0

@MooingDuck,其他人:谢谢。正是我需要的。 – fredbaba

1

您不能使用可变参数的参数列表,除非它是一个模板,你可以,如前所述,使用这样的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...}); 
} 
+0

你为什么有辅助功能? –

+0

@MooingDuck只是为了显示variadic模板参数的使用 –

4
// 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*>,那么会自动发生,然后您不需要任何丑陋的012BSFINAE技巧。

1

另一种方式来做到这一点:

#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; 
} 
1
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); 
} 

来自实例C++ 11周的真相看起来很简单...;) 不是一个完整的解决方案,但可能给你一些想法。

+0

这适用于你的'b1'和'b2'的例子,但是OP想做'Blob b3 {“Circle”,“Triangle”,“Square”};'和你的'Blob'构造函数不能做到这一点,因为你使用'_v'的值初始化。如果将其更改为使用'_v'的列表初始化,它将支持OP想要执行的操作。 –