2013-05-16 11 views
30

Jak zadeklarować klasę szablonu (adapter) z różnymi kontenerami jako argumenty szablonu? Na przykład, muszę zadeklarować klasę:Klasa szablonu z kontenerem szablonu

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

I chcę go do mojego oparte na wektorze. Jak to utrudnić? (aby uniemożliwić komuś napisanie takiej deklaracji MyMultibyteString<int, vector<char>>).

Ponadto, jak wdrożyć taką konstrukcję:

MyMultibyteString<int, std::vector> mbs; 

bez przechodzenia szablonu argumentu do pojemnika.

Odpowiedz

59

Należy użyć parametrów szablonu szablon:

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

Pozwoliłoby to napisać:

MyMultibyteString<int, std::vector> mbs; 

Oto kompilacja live example. Alternatywnym sposobem pisania powyżej mogą być:

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 
    // ... 
}; 

I tu jest odpowiedni live example.

Należy zwrócić uwagę na to, że liczba i typ argumentów w deklaracji parametru szablonu szablonu musi dokładnie odpowiadać liczbie i typowi argumentów w definicji odpowiedniego szablonu klasy, który ma zostać przekazany jako argument szablonu, niezależnie od faktu, że niektóre z tych parametrów mogą mieć wartości domyślne.

Na przykład: the class template std::vector accepts two template parameters (typ elementu i typ alokatora), chociaż drugi ma domyślną wartość std::allocator<T>. Z tego powodu nie można napisać:

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) 

Oznacza to, że nie będzie w stanie napisać pojedynczą klasę szablonu, który można zaakceptować zarówno std::set i std::vector jako parametr szablonu szablonu, ponieważ w odróżnieniu od std::vector, the std::set class template accepts three template parameters.

+0

Co za wspaniały, dokładne odpowiedzi. –

+0

@ScottJones: Cieszę się, że znalazłeś przydatne :) –

+3

@ScottJones Odnosząc się do twojego oświadczenia: 'Oznacza to, że nie będziesz w stanie napisać jednego szablonu klasy, który może zaakceptować zarówno std :: set, jak i std :: vector': szablony variadyczne rozwiązują problem? http://stackoverflow.com/a/20499809/2436175 – Antonio

2

Innym podejściem do rozwiązania tego problemu jest użycie zmiennej liczbie argumentów szablony i że można użyć dowolnego pojemnika jak zasugerowano w powyższych uwag, a tutaj jest implementacja:

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; 
} 
Powiązane problemy