2013-05-16 18 views
30

Come posso dichiarare la classe template (adattatore) con contenitori diversi come argomenti del modello? Per esempio, ho bisogno di dichiarare classe:Classe template con contenitore modello

template<typename T, typename Container> 
class MyMultibyteString 
{ 
    Container buffer; 
    ... 
}; 

E voglio che la mia base di vettore. Come renderlo ben definito? (per impedire a qualcuno di scrivere tale dichiarazione MyMultibyteString<int, vector<char>>).

Inoltre, come implementare tale costruzione:

MyMultibyteString<int, std::vector> mbs; 

senza passare argomento di template di contenitore.

risposta

59

Si dovrebbe usare parametri di modello template:

template<typename T, template <typename, typename> class Container> 
//     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
class MyMultibyteString 
{ 
    Container<T, std::allocator<T>> buffer; 
    // ... 
}; 

Questo permetterebbe di scrivere:

MyMultibyteString<int, std::vector> mbs; 

Qui è una compilazione live example. Un modo alternativo di scrivere quanto sopra potrebbe essere:

template<typename T, 
    template <typename, typename = std::allocator<T>> class Container> 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
class MyMultibyteString 
{ 
    Container<T> buffer; // <== No more need to specify the second argument here 
    // ... 
}; 

Ed ecco la corrispondente live example.

L'unica cosa a cui prestare attenzione è che il numero e il tipo di argomenti nella dichiarazione dei parametri del modello di modello deve corrispondere esattamente al numero e al tipo di argomenti nella definizione del modello di classe corrispondente che si desidera passare come argomento modello, indipendentemente dal fatto che alcuni di questi parametri possano avere valori predefiniti.

Ad esempio, the class template std::vector accepts two template parameters (il tipo di elemento e il tipo di allocatore), sebbene il secondo abbia il valore predefinito std::allocator<T>. A causa di questo, si potrebbe non scrittura:

template<typename T, template <typename> class Container> 
//        ^^^^^^^^ 
//        Notice: just one template parameter declared! 
class MyMultibyteString 
{ 
    Container<T> buffer; 
    // ... 
}; 

// ... 

MyMultibyteString<int, std::vector> mbs; // ERROR! 
//      ^^^^^^^^^^^ 
//      The std::vector class template accepts *two* 
//      template parameters (even though the second 
//      one has a default argument) 

Questo significa che non sarà in grado di scrivere un modello di classe singola che può accettare sia std::set e std::vector come parametro di template, perché a differenza di std::vector, the std::set class template accepts three template parameters.

+0

Che grande, risposta esauriente. –

+0

@ScottJones: Sono contento che tu l'abbia trovato utile :) –

+3

@ScottJones Per quanto riguarda la tua affermazione: 'Ciò significa che non sarai in grado di scrivere un modello di classe singolo che possa accettare sia std :: set che std :: vector': Would i modelli variadici risolvono il problema? http://stackoverflow.com/a/20499809/2436175 – Antonio

2

Un altro approccio per risolvere questo è quello di utilizzare i modelli variadic e che è possibile utilizzare qualsiasi contenitore come suggerito nei commenti di cui sopra e qui è l'implemenation:

template<template <typename... Args> class Container,typename... Types> 
class Test 
{ 
    public: 
    Container<Types...> test; 

}; 
int main() 
{ 
    Test<std::vector,int> t; 
    Test<std::set,std::string> p; 
    return 0; 
} 
Problemi correlati