2017-06-20 3 views
2

ich ein sehr einfaches Testprogramm wie unten haben:C++: Warum kann mit der Vorlage nicht sowohl der Container- als auch der Elementtyp abgeleitet werden?

#include<vector> 
#include<iostream> 
using namespace std; 
template<typename C, typename E> 
void f(const C<E>& container){ 
    cout<<container.size()<<endl; 
} 
int main(){ 
    vector<int> i; 
    f(i); 
    return 0; 
} 

Es scheitert mit gcc 4.1.2 zu kompilieren. Fehlermeldung lautet:

templateContainer.cpp:5: error: ‘C’ is not a template 
templateContainer.cpp: In function ‘int main()’: 
templateContainer.cpp:10: error: no matching function for call to ‘f(std::vector<int, std::allocator<int> >&)’ 
+1

Aus diesem Grund haben Container einen * zugeordneten Typ *. Du brauchst kein 'E'; Schreiben Sie einfach 'typename C :: value_type' (oder' typename C :: reference_type', wie passend). –

+0

Zur Verdeutlichung, die Fehlermeldung ist, weil 'C ** ist definiert ** als der Name eines Typs (' typename C '), aber es ist ** verwendet ** als der Name einer Vorlage ('C ') . Es kann nicht beides sein. –

Antwort

9

Sie könnten verwenden, um eine Template-Template-Parameter (und beachten Sie, dass std::vector tatsächlich mehr als ein Template-Parameter nimmt [einen Elementtyp und ein allocator Typ]) .:

template<template <typename...> class C, typename... E> 
void f(const C<E...>& container){ 
    cout<<container.size()<<endl; 
} 

Live Demo


Wenn Sie die Art Zersetzungen nicht benötigen, können Sie einfach verwenden ein o gewöhnliche Vorlage.

template<typename C> 
void f(const C& container){ 
    cout<<container.size()<<endl; 
} 

Sie zusätzlich typedefs von STL-Containern erhalten können: zum Beispiel, wenn Sie den Typen von Elementen durch den Behälter gehalten wissen wollen, ist value_type für Sie da.

template<typename C> 
void f(const C& container){ 
    using ValueType = typename C::value_type; 
    cout<<container.size()<<endl; 
} 
+0

ohne variadic Vorlagen (dh C++ 11) müsste man die Anzahl der Parameter im Voraus wissen? – user463035818

+0

@ tobi303, Yep, Sonst, einige alte unangenehme Trick der Überlastung mit vielen vielen Template-Parameter – WhiZTiM

+2

Beachten Sie, dass, während dies definitiv richtige Antwort auf die Frage wie gesagt, wenn Sie tatsächlich verwenden, um den Werttyp eines Containers abzuleiten, verdienen Sie auf der Stelle gefeuert werden.Container haben typedefs für die zugehörigen Typen und Sie sollten diese immer verwenden. Weil der Containervertrag diese erfordert und * nicht * erfordert, dass der Werttyp überhaupt ein Vorlagenargument ist. –

1

std :: vector hat zwei Vorlagenargumente, Typ und Zuweiser.

template <template<class, class> class C, class E, class A> 
void f(const C<E, A> &container) 
{ 
    std::cout << container.size() << endl; 
} 

int main() 
{ 
    std::vector<int> i; 
    f(i); 
    return 0; 
} 
1

Obwohl WhiZTiM Antwort korrekt ist (na ja, den zweiten Teil vorzieht), ist es nicht erklären, warum Ihr Code funktioniert nicht.

Unter der Annahme, für den Moment, dass Sie in etwa

bestimmt
template<template <typename> class C, typename E> void f(const C<E>&); 

den Grund, dass std::vector nicht der Fall überein, dass es die falsche Form ist - es hat zwei Typparametern, nicht ein wie in Ihrer Erklärung.

Nur weil Sie nicht oft explizit schreiben Sie den voreingestellten zweiten (allocator) param, bedeutet nicht, dass es nicht da ist.

Zum Vergleich, das funktioniert (oder nicht) in analoger Weise:

void f(int); 
void g(int, int* = nullptr); 

void apply(void (*func)(int), int); 

apply(f, 42); // ok - f matches shape void(*)(int) 
apply(g, 42); // error - g is really void(*)(int,int*) 

gesagt Standardargumente (oder Typ-Parameter) sind syntaktischer Zucker. Sie ermöglichen es Ihnen, diese Argumente an der Aufruf- (Instanziierungs-) Site zu vergessen, aber ändern Sie nicht die Form der Funktion (oder der Vorlage).

Verwandte Themen