2012-12-20 28 views
22

Perdonami se è già stata data una risposta, poiché non ho potuto trovarlo ...Inserimento di una lista di argomenti variadici in un vettore?

Fondamentalmente ho un oggetto che deve prendere una lista di argomenti variadici nel suo costruttore e memorizzare gli argomenti in un vettore. Come si inizializza un vettore da un argomento di un costruttore variadic?

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

C'è qualche sintassi non valida nell'esempio. Cosa stai specificatamente cercando di chiedere? –

+8

usa 'std :: initializer_list '. –

+0

Siamo spiacenti. Per chiarire, come posso usare la lista degli argomenti per compilare un vettore std ::? @MooingDuck, guarderò in std :: initializer_list. Grazie. – fredbaba

risposta

22

Il migliore cosa sarebbe quella di utilizzare un lista di inizializzazione

#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 

il più vicino a ciò che già avete, utilizzando C++ 11 è quello di utilizzare initializer_list del vettore:

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

E qui c'è una versione C++ 11 senza inizializzazioni_lista. È brutto e complicato e richiede funzionalità mancanti in molti compilatori. Utilizzare la lista di inizializzazione

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 

Estranei a tutto ciò, non so se queste sono proprietarie di puntatori o meno. Se lo sono, utilizzare invece std::unique_ptr.

+0

Non 'template GenericNode (T * ... input): inputs_ {inputs ...} {}' essere più vicino a ciò che ha già? andrei comunque con 'std :: initializer_list '. –

+0

@JonathanWakely: Non ho idea del perché non ci ho mai pensato. Fisso. –

+0

@MooingDuck, altri: Grazie. Proprio quello di cui avevo bisogno. – fredbaba

1

Non è possibile utilizzare un elenco di argomenti variadic a meno che non si tratta di un modello, è possibile, come detto, usare un initializer_list come questo:

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

Perché hai la funzione di aiuto? –

+0

@MooingDuck Giusto per mostrare l'uso dei parametri del modello variadico –

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

Questo non funziona perché non è possibile espandere un parametro pacchetto come una dichiarazione, solo in certi contesti, come una lista di argomenti di funzione o di inizializzazione-list.

Anche la firma del costruttore è sbagliata, se stai provando a scrivere un modello variadico deve essere un modello!

Una volta che si scrive la propria firma costruttore correttamente la risposta è semplice, basta costruire il vettore con l'Expansion Pack:

#include <vector> 

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

(Si potrebbe invece hanno creato nel corpo costruttore con:

inputs_ = { inputs... }; 

ma i bambini fantastici utilizzano gli inizializzatori dei membri non assegnati nel corpo del costruttore.)

Lo svantaggio di questa soluzione è che il modello costruisce o accetta qualsiasi tipo di argomento del puntatore, ma darà un errore quando tenterà di costruire il vettore se gli argomenti non sono convertibili in GenericNode*. Potresti limitare il modello ad accettare solo i puntatori GenericNode, ma questo è ciò che accade automaticamente se fai ciò che suggeriscono le altre risposte e fai in modo che il costruttore prenda un std::initializer_list<GenericNode*>, e quindi non hai bisogno di brutti scherzi di enable_if SFINAE.

1

Un altro modo per farlo:

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

Esempio da C++ 11 Verità sembra abbastanza semplice ...;) non è una soluzione completa, ma potrebbe dare qualche idea.

+0

Funziona bene per gli esempi 'b1' e' b2', ma l'OP vuole fare 'Blob b3 {" Circle "," Triangle "," Square "};' e il costruttore 'Blob' non può farlo , perché usi l'inizializzazione del valore per '_v'. Se lo cambi per usare l'inizializzazione della lista per '_v', sosterrebbe ciò che l'OP vuole fare. –

Problemi correlati