2012-12-20 53 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想要執行的操作。 –