2013-05-15 15 views
5

Ich arbeite meinen Weg durch beschleunigtes C++ & haben ein Problem mit Ex. 10.2 Die Frage beinhaltet das Neuschreiben einer Medianfunktion aus einem vorherigen Kapitel, so dass nun der Median mit einem Vektor oder einem eingebauten Array aufgerufen werden kann. Die Median-Funktion sollte auch Container beliebiger arithmetischer Art erlauben.Fehler mit Vorlagen: keine passende Funktionsaufruf

Ich kann nicht die beiden Anrufe zu Median detaillierten unten machen - ich die Fehlermeldung

No matching function for call to 'median' 

ich von einigen der Forschung zu sammeln, dass, wenn Vorlagen verwendet werden, die Art sollte zum Zeitpunkt der Kompilierung bekannt sein. Könnte dies das zugrunde liegende Problem sein? Gibt es eine Möglichkeit, den Type als Template-Argument irgendwie zu übergeben?

Hier ist mein Code so weit:

#include <iostream> 
#include <vector> 
#include <stdexcept> 
#include <algorithm> 
#include <cstddef> 

using namespace std; 

template <class Iterator, class Type> 
Type median(Iterator begin, Iterator end) 
{ 
    vector<Type> vec(begin,end); 
    typedef typename vector<Type>::size_type container_sz; 
    container_sz size = vec.size(); 

    if (size == 0) { 
     throw domain_error("median of an empty vector"); 
    } 

    sort(vec.begin(), vec.end()); 

    container_sz mid = size/2; 
    return size % 2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid]; 
} 

int main() 
{ 
    vector<int> grades; 

    for (int i = 0; i != 10; ++i){ 
     grades.push_back(i); 
    } 

    const int int_array[] = {2, 9, 4, 6, 15}; 
    size_t array_size = sizeof(int_array)/sizeof(*int_array); 

    cout << median(int_array, int_array + array_size) << endl; //error here: Semantic Issue, No matching function for call to 'median' 
    cout << median(grades.begin(), grades.end()) << endl;  //error here: Semantic Issue, No matching function for call to 'median' " 

    return 0; 
} 
+1

Wenn Sie C++ 11 verwenden, können Sie den Vektor mit 'Vektor Typen initialisieren = {0, 1, 2, 3, 4 , 5, 6, 7, 8, 9} 'und' auto size = vec.size(); '(dh Entfernen des typedef). Sie können 'endl' auch durch' \ n "' ersetzen, wenn Sie möchten. –

+0

Für First-Pass-Leser profitieren, bitte markieren Sie die Zeile (einschließlich * beide *, wenn das der Fall ist), die Ihren Kompilierungsfehler verursacht, mit einem Kommentar (zB '// <== Fehler hier). Allerdings kann der Template-Parameter 'Type' nicht aus den von Ihnen ausgeführten Calls abgeleitet werden, was letztendlich das Kernproblem darstellt. Ich denke, das von der Standardbibliothek bereitgestellte Template ['iterator_traits'] (http://en.cppreference.com/w/cpp/iterator/iterator_traits) könnte eine saubere Lösung für Ihr Problem sein. – WhozCraig

+0

Und bitte die vollständige Fehlermeldung enthalten. In der Regel wird angegeben, welche Typen im Funktionsaufruf abgeleitet werden, die Sie mit den tatsächlich erwarteten Typen vergleichen können. –

Antwort

3

Ihr Fehler wird im Abzug der Type verwurzelt, die mit den angegebenen Argumenten nicht möglich ist. Sie können tun dies die Standard-Bibliothek-Klasse iterator_traits wie folgt:

template < 
    class Iterator, 
    class Type = typename std::iterator_traits<Iterator>::value_type> 
Type median(Iterator begin, Iterator end) 
{ 
    vector<Type> vec(begin,end); 

    typedef typename vector<Type>::size_type container_sz; 

    container_sz size = vec.size(); 

    if (size == 0) { 
     throw domain_error("median of an empty vector"); 
    } 

    sort(vec.begin(), vec.end()); 

    container_sz mid = size/2; 

    return size % 2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid]; 
} 

Die Klasse iterator_traits seziert die Iterator-Typ zur Verfügung gestellt, um zu bestimmen, was es tatsächlich Iterieren ist (ein wenig komplizierter als das, aber das ist ein anständiger Zusammenfassung). Weitere Informationen zur Funktionsweise finden Sie in der Dokumentation von class iterator_traits. Es ist ein äußerst praktischer Mechanismus zum Bestimmen von Iterator-Werttypen.

Hinweis: keine unbeabsichtigten Bypässe der Standard-Template-Parameter Type Erklärung sicherzustellen, dass Sie dies auch tun können:

template <class Iterator> 
typename std::iterator_traits<Iterator>::value_type median(Iterator begin, Iterator end) 
{ 
    if (begin == end) 
     throw domain_error("median of an empty vector"); 

    typedef typename std::iterator_traits<Iterator>::value_type Type; 
    std::vector<Type> vec(begin,end); 
    sort(vec.begin(), vec.end()); 

    typename std::vector<Type>::size_type mid = vec.size()/2; 
    return vec.size() % 2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid]; 
} 

Es ist ein wenig dicht, und wirft die größten Teil der Zwischen Sachen aus, aber wenn Sie starren auf Es ist lange genug, dass Sie verstehen, wie es funktioniert, und es reduziert Ihre Template-Parameterliste, um nur das zu verwenden, was Ihnen wirklich wichtig ist. Der Typ Iterator, der trivialerweise von den Parametern abgeleitet wird, die Sie der Funktion zur Verfügung stellen.

+0

Ich habe oben einen Kommentar mit einem Link zur Lösung des Autors für das Problem geschrieben (https://github.com/bitsai/book-exercises/blob/master/Accelerated%20C%2B%2B/chapter10/10-2.hpp) Wie ich bereits erwähnt habe, sieht deine Lösung perfekt aus, aber ich habe es noch nicht in dem Buch gefunden, was darauf hindeutet, dass ich etwas vermisse? – Octave1

+0

@ Octave1 Ebenso. Ich hoffe es macht Sinn. – WhozCraig

+0

Sorry, der erste Kommentar wurde zu früh gepostet, jetzt bearbeitet. Danke für die Antwort. Ich denke, iterator_traits wird nützlich sein. Was ich nicht verstehe ist, dass die Lösung des Autors den gleichen Fehler macht wie ich, indem ich den Typ aus den gegebenen Iterator-Argumenten ableite. Irgendwelche Ideen? – Octave1

4

Der beste Weg, dieses Problem im Allgemeinen zu lösen, ist die Verwendung von iterator_traits wie oben beschrieben. Um jedoch die spezielle Frage 10.2 aus dem Buch zu beantworten (die Iterator_trait Wissen nicht voraussetzt), kann man wie folgt vorgehen: - Hinweis Klasse Typ muss zuerst statt Klasse Iterator aufgeführt werden. Außerdem muß man median<int>(grades.begin(), grades.end()) nennen, im Gegensatz zu median(grades.begin(), grades.end())

#include <iostream> 
#include <vector> 
#include <stdexcept> 
#include <algorithm> 
#include <cstddef> 

using namespace std; 

template <class Type, class Iterator>  //the order allows the second template parameter type to be deduced (Iterator)           
Type median(Iterator begin, Iterator end) //while requiring you still provide the first type 
{ 

    vector<Type> vec(begin,end); 

    //typedef typename vector<Type>::size_type container_sz; 
    //container_sz size = vec.size() 
    auto size = vec.size(); 

    if (size == 0) { 
     throw domain_error("median of an empty vector"); 
    } 

    sort(vec.begin(), vec.end()); 

    //container_sz mid = size/2 
    auto mid = size/2; 

    Type ret = size % 2 == 0 ? (vec[mid] + vec[mid - 1])/2 : vec[mid]; 

    return ret; 
} 


int main() 
{ 

    vector<int> grades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 

    const int int_array[] = {2, 9, 4, 6, 15}; 

    size_t array_size = sizeof(int_array)/sizeof(*int_array); 

    cout << median<int>(int_array, int_array + array_size) << endl; //must provide int here, in order to give the template the return type at compile time 
    cout << median<int>(grades.begin(), grades.end()) << endl; 


return 0; 

}
Verwandte Themen