2013-05-15 16 views
5

Pracuję na mojej drodze poprzez przyspieszone C++ & trafiłem na problem z Ex. 10.2 Pytania dotyczą przepisywania funkcji mediany z poprzedniego rozdziału, aby teraz medianę można było wywoływać za pomocą wektora lub wbudowanej tablicy. Funkcja mediana powinna także umożliwiać pojemniki dowolnego typu arytmetycznego.Błąd przy szablonach: brak pasującej funkcji zadzwoń

nie mogę zrobić dwa połączenia do środkowej szczegółowy poniżej - pojawia się komunikat o błędzie

No matching function for call to 'median' 

wnoszę z niektórych badań, które, gdy są używane szablony Type powinien być znany w czasie kompilacji. Czy to może być podstawowy problem? Czy istnieje sposób, aby jakoś przekazać typ jako argument szablonu?

Oto mój kod do tej pory:

#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

Jeśli używasz C++ 11 można zainicjować wektora z wektorem klas '= {0, 1, 2, 3, 4 , 5, 6, 7, 8, 9} 'i' auto size = vec.size(); '(tj. Usunięcie typedef). Możesz również zamienić 'endl' na' "\ n" 'jeśli chcesz. –

+0

W przypadku korzystania z czytników pierwszego przejścia, uprzejmie zaznacz, który wiersz (w tym * oba * jeśli tak jest), powoduje błąd kompilacji z komentarzem (np. '// <== błąd tutaj"). To powiedziawszy, parametru szablonu "Typ' nie można wyprowadzić z wywołań, które tworzysz, co jest ostatecznie głównym problemem. Myślę, że szablon dostarczony przez bibliotekę standardową [iterator_traits'] (http://en.cppreference.com/w/cpp/iterator/iterator_traits) może być czystym rozwiązaniem twojego problemu. – WhozCraig

+0

Proszę podać pełny komunikat o błędzie. Zwykle mówi, jakie typy dedukuje w wywołaniu funkcji, które można porównać z rzeczywistymi oczekiwanymi typami. –

Odpowiedz

3

Twój błąd jest zakorzenione w odliczeniu Type co nie jest możliwe z argumentów przedstawionych. Ci może to zrobić przy użyciu standardowego Class Library iterator_traits następująco:

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]; 
} 

Klasa iterator_traits rozcina typu Iterator przewidzianego do określenia, co to jest rzeczywiście Iteracja (trochę bardziej skomplikowana, ale to jest przyzwoity Podsumowanie). Więcej informacji o tym, jak to działa, znajdziesz w dokumentacji class iterator_traits. Jest to najbardziej poręczny mechanizm do określania typów wartości iteratorów.

Uwaga: aby zapewnić nie niezamierzone obwodnic parametru Domyślny szablon Type deklaracji można też to zrobić:

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]; 
} 

Jest trochę gęste i wyrzuca większość pośredniego rzeczy, ale jeśli spojrzeć na wystarczająco długo zrozumiesz, jak to działa, i zmniejsza listę parametrów szablonu, aby używać tylko jednej rzeczy, na której Ci zależy; typ Iterator, który jest trywialnie wydedukowany przez parametry podane do funkcji.

+0

Napisałem komentarz powyżej z linkiem do rozwiązania autora problemu (https://github.com/bitsai/book-exercises/blob/master/Accelerated%20C%2B%2B/chapter10/10-2.hpp) Jak już wspomniałem, twoje rozwiązanie wygląda idealnie, ale nie natknąłem się jeszcze na niego w książce, co sugeruje, że brakuje mi czegoś? – Octave1

+0

@ Octave1 Podobnie. Mam nadzieję, że to ma sens. – WhozCraig

+0

Przepraszamy, pierwszy komentarz został opublikowany za wcześnie, teraz edytowany. Dziękuję za odpowiedź. Myślę, że iterator_traits przyda się. Nie rozumiem, że rozwiązanie autora wydaje się popełniać ten sam błąd co mój, przez dedukowanie typu z podanych argumentów iteratora. Jakieś pomysły? – Octave1

4

Najlepszym sposobem na rozwiązanie tego problemu jest generalnie użycie iterator_traits zgodnie z powyższym opisem. Jednakże, aby odpowiedzieć na konkretne pytanie 10.2 z książki (która nie przyjmuje wiedzy Iterator_trait), można postępować w następujący sposób: - Uwaga Typ klasy musi być wymieniony jako pierwszy, a nie jako Iterator klasy. Ponadto, trzeba zadzwonić median<int>(grades.begin(), grades.end()) w przeciwieństwie do 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; 

}

Powiązane problemy