2013-09-04 37 views
6

Próbuję przekazać kontener STL jako parametr szablonu. W tym przypadku wektor.Kontener STL jako parametr szablonu

Oto mój kod nie-funkcjonalny:

template<template<class> class TContainer, class TObject> 
class Foobar 
{ 
public: 

    explicit Foobar(TContainer<TObject*> & container) 
    : 
    container_(container){} 


private: 

    TContainer<TObject*> & container_; 
}; 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::vector<IUnknown*> v; 

    Foobar<std::vector, IUnknown*> bla(v); 

    return 0; 
} 

Czy to, co usiłuję zrobić to w ogóle możliwe, ponieważ kompilator nie może przełknąć to?

+0

@itwasntpete, bardzo pomocne, dziękuję. – moose

+0

mój pierwszy komentarz był żartem ... ale w twoim kodzie jest sporo problemów. również przekazanie typu (int) i określonej klasy szablonów (wektor ) jest również kwestią projektowania. możesz zacząć jak [tutaj] (http://ideone.com/i00l0t). – user1810087

+0

zarzutów wyjaśnić, dlaczego nie jest funkcjonalny i czego się spodziewać? –

Odpowiedz

12

Istnieje kilka rzeczy źle z kodem, tutaj jest przykład roboczych:

template<template<class, class> class TContainer, class TObject> 
class Foobar 
{ 
public: 
    explicit Foobar(TContainer<TObject*, std::allocator<TObject*>> & container) 
    : 
    container_(container){} 

private: 
    TContainer<TObject*, std::allocator<TObject*>> & container_; 
}; 

int main() 
{ 
    std::vector<IUnknown*> v; 
    Foobar<std::vector, IUnknown> bla(v); 
} 

Główną wadą kodów to, że std::vector przyjmuje dwa argumenty szablonu. Wygląda to tak: template<class T, class Allocator = std::allocator<T>> class vector;. Ponadto, Joachim Pileborg ma rację co do problemu z podwójnym wskaźnikiem, IUnknown**. Jednak można uprościć kod z następujących czynności:

template<class TContainer> 
class Foobar 
{ 
public: 
    explicit Foobar(TContainer & container) 
    : 
    container_(container){} 

private: 
    TContainer & container_; // Be careful with reference members 
}; 

int main() 
{ 
    std::vector<IUnknown*> v; 
    Foobar<std::vector<IUnknown*>> bla(v); // C++11 decltype(v) could be used 
} 
+1

Jeśli chodzi o wersję uproszczoną, skąd wiadomo, jaki typ znajduje się w wektorze? (Załóżmy, że chcesz użyć for_each na 'container_' wewnątrz Foobar.) – moose

+0

@moose: 'typename TContainer :: value_type' dałoby ci typ w wektorze. Nie jestem pewien, dlaczego potrzebujesz tego z for_each. –

+0

jeśli używam funkcji lambda z for_each, potrzebuję "TContainer :: value_type" jako argumentu lambda. – moose

0

Na początek prawdopodobnie pojawią się błędy kompilatora, więc powinieneś dodać je do pytania, ponieważ teraz możemy tylko zgadywać.

Po drugie, jestem zgadywania że to z powodu swojej parametru szablonu:

Foobar<std::vector, IUnknown*> bla(v); 
//     ^^^^^^^^^ 

Tutaj poinformować kompilator, że parametr szablonu jest wskaźnikiem, ale potem trzeba konstruktora:

Foobar(TContainer<TObject*> & container) 
//     ^^^^^^^^ 

W konstruktorze deklarowania container aby być TContainer z TObject* członków, ale od TObject już jest wskaźnikiem masz teraz wskaźnik do wskaźnika. Jeśli TObject jest równy IUnknown*, wówczas TObject* jest równy IUnknown**. Ten sam problem występuje podczas deklarowania zmiennej składowej container_.

polecam spadek wskaźnika typu podczas deklarowania bla:

Foobar<std::vector, IUnknown> bla(v); 
//     ^^^^^^^^ 
+0

AFAIK, zgodnie z mojego kodu powyżej, TObject = IUnknown *. – moose

+0

@moose Tak, i dodajesz kolejną gwiazdkę do 'TObject' tworząc' TObject * 'tak samo jak' IUnknown ** '. –

+0

Przykro mi, ale jesteś w błędzie. – moose

0

może utworzyć synonim typu wektorowych z typedef w celu uproszczenia kodowania.

typedef vector<MyClass> List; 

Następnie użyj Lista jako parametru szablonu jako "zwykłego" typu.

template<class T, class K> 
class Foobar {...} 

Foobar<List> variable; 
6

Istnieją trzy różne rodzaje argumentów szablonu: wartości, typy i szablony:

template <int value_argument> class C { }; 
template <class type_argument> class D { }; 
template <template<classT> class template_argument> class E { }; 

Podczas korzystania z tych szablonów musisz Podaj argument prawidłowego rodzaju:

C<3> c; 
D<int> d; 
E<C> e; 

Podczas korzystania z trzeciego formularza, szablon szablonu argument, szablon przekazany jako argument musi mat ch deklaracja argumentu szablonu szablonu. W moich prostych przykładach szablon oczekuje od szablonu szablonu argumentu, który przyjmuje jeden typ argumentu.

W kodzie w pytaniu, pierwszym argumentem w deklaracji Foobar jest template <class> class TContainer. W miejscu, gdzie jest on używany, szablon, który jest przekazywane jest std::vector:

Foobar<std::vector, IUnknown*> bla(v); 

Problem polega na tym, że argument szablonu szablon mówi, że powinien on mieć jeden argument, ale szablon, który jest przekazywany jako rzeczywistą argumentu ma dwa lub więcej . Formalnie std::vector jest

template <class T, class Allocator = std::allocator<T>> class vector { ... }; 

Aby korzystać std::vector> as the first argument to Foobar , the definition of Foobar` musi zostać zmieniony tak, że pierwszy argument przyjmuje dwa argumenty typu:

template <template<class, class> TContainer, class TObject> class Foobar { ... }; 
+0

+1 dla wyjaśnienia, ale głównym problemem w tym przypadku jest to, że pierwszym argumentem na 'Foobar' jest szablon z nieprawidłową liczbą argumentów (2 zamiast oczekiwanego 1). – juanchopanza

+0

@juanchopanza - gack. Masz rację. Korekta ... –

7

Inną możliwością jest, aby TContainer o zmiennej liczbie argumentów szablonu :

+0

VS2010 nie może tego skompilować. Wygląda na to, że problemem jest "". – moose

+0

@moose Tak, VS nie obsługuje jeszcze variadics. Powinien jednak pracować w VS 2013. – catscradle

Powiązane problemy