2014-07-09 11 views
9

Sto tentando di implementare una classe vettoriale n-dimensionale generalizzata utilizzando C++ 11. Idealmente, mi piacerebbe fornire il tipo "T" e il numero di dimensioni "n" del vettore e fare in modo che il costruttore accetti il ​​numero appropriato di argomenti.Pacchetti parametri variabili a lunghezza fissa in C++ 11

Purtroppo, non sono stato in grado di trovare un modo per consentire una lunghezza fissa specificata da un modello di un pacchetto di parametri.

Quello che sto cercando è qualcosa di simile

template<typename T, size_t n> 
class Vector { 
public: 
    Vector(T... values /* values is exactly n parameters long */); 

    ... 
}; 

E 'possibile fare questo?

+3

C'è 'std :: array' per questo. – 101010

risposta

13

Beh, è ​​possibile utilizzare std :: enable_if:

template <typename... Args, 
    typename = typename std::enable_if< 
     sizeof...(Args) == n 
    >::type> 
explicit Vector(Args&&... values) : _data{ std::forward<Args>(values)... } {} 

Sarà ombra costruttori che possono accettare dimensioni Args diverso da n.

+0

Interessante. Potresti spiegare esattamente cosa sta succedendo nella lista di inizializzazione del costruttore? Sono abbastanza nuovo per lo standard C++ 11 e sto avendo difficoltà a capire come funziona. Grazie! –

+1

È semplicemente un semplice costruttore di mosse. Ho assunto che __data sia definito in questo modo: T __data [n]; l'elenco di inizializzatori sposta semplicemente i valori dagli argomenti del costruttore all'array __data. Dovresti leggere su std :: move, è davvero fantastico. – Garrappachc

+3

Nota che uno o due prefissi underscore sono spesso usati dai compilatori ... – jiggunjer

3

si potrebbe anche usare questo trucco:

template <typename T, std::size_t n, typename = std::make_index_sequence<n>> 
class Vector; 

template <typename T, std::size_t n, std::size_t... Ignore> 
class Vector<T, n, std::index_sequence<Ignore...>> 
{ 
    template <size_t > using ith_T = T; 
public: 
    Vector(ith_T<Ignore>... values) 
    { 
    } 
}; 

Questo farà sì che Vector prende n argomenti di tipo T, senza template aggiuntivi necessari. Si potrebbe inoltre nascondere l'Ignore... bruttura in uno spazio dei nomi:

namespace details { 
    template <typename T, std::size_t n, typename = std::make_index_sequence<n>> 
    class Vector; 

    ... 
} 

template <typename T, std::size_t n> 
using Vector = details::Vector<T, n>; 
+0

Potresti spiegare un po 'cosa succede qui? – Kikohs

+0

@Kikohs Viene creato un pacchetto della lunghezza giusta (tramite un argomento predefinito e 'make_index_sequence'). Questo pacchetto è abbinato alla specializzazione. Questo pacchetto viene quindi decompresso in modo che ogni istanza diventi il ​​tipo "T". Otteniamo un ctor che richiede esattamente 'n' istanze di' T'. Non mi piace l'uso che Barry fa di 'details :: make' (Perché usare' decltype' affatto? 'Template usando ith_T = T; Vector (ith_T ...)'), e se l'utente finale passa un terzo argomento difettoso, le cose si fanno a pezzi, ma a parte questo, funziona. – Yakk

+0

@Yakk Questo è decisamente migliore, sì. – Barry