2013-08-22 13 views
6

W moim programie C++ próbuję sortować mapy według wartości, a nie według klucza.Dlaczego muszę powtarzać podprogram sortowania podczas deklarowania std :: set?

Od this question wydaje się jasne, że sposobem na to jest stworzenie zestawu, którego elementy są parami i które są sortowane według mojej własnej funkcji niższej.

Oto przykładowy kod gdzie staram się to zrobić:

#include <map> 
#include <set> 
#include <iostream> 
#include <string> 

using namespace std; 

bool compareCounts(const pair<string, size_t> &lhs, const pair<string, size_t> &rhs); 

int main (int argc, char *argv[]) { 
     map <string, size_t> counter = { {"A", 1}, {"B", 2}, {"C", 3} }; 
     set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter; 
     for (map<string, size_t>::iterator it = counter.begin(); it != counter.end(); ++it) { 
       cout << "About to add: " << it->first << ":" << it->second << endl; 
       auto ret = sorted_counter.insert(*it); 
       if (! ret.second) { 
         cout << "ERROR adding this element!" << endl; 
       } else { 
         cout << "Element added ok" << endl; 
       } 
       cout << "Set is of size: " << sorted_counter.size() << endl; 
     } 

     return 0; 
} 

bool compareCounts(const pair<string, size_t> &lhs, const pair<string, size_t> &rhs) { 
     return lhs.second > rhs.second; 
} 

Oto wynik:

O dodać: A: 1
Element dodany ok
Zestaw jest o rozmiarze: 1
O dodaniu: B: 2
Błąd segmentacji: 11

Zauważyłem, że coś się zawiesza, kiedy idę, aby dodać drugi element. Stwierdziłem, że tak się dzieje, ponieważ teraz konieczne jest wywoływanie mojego podprogramu sortowania, compareCounts.

Rozwiązaniem było zmienić tę linię:

set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter; 

do tego:

set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter(compareCounts); 

Dlaczego muszę podać sortowania podprogram compareCounts dwukrotnie? Czy kompilator nie zna już tego z definicji mojego typu?

+0

co używasz, 'map' lub' set'? to jest dość mylące. proszę podać samodzielny przykład: – TemplateRex

+0

Używam zestawów do sortowania map według wartości. – EMiller

+0

Czy jest to rzecz na żądanie lub ciągłe parowanie obu struktur (zdecydowanie odradzam)? Czy na żądanie, czy rozważasz po prostu wyrzucenie 'std :: ref >' do wektora i wypalenie 'std :: sort()' z własnym komparatorem? – WhozCraig

Odpowiedz

6
set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter; 

Nigdy nie podano, który kompilator powinien w rzeczywistości używać set. Zmienić powyższą linię do

set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter(compareCounts); 

Bez komparator jest określony, domyślnie set konstruuje jeden (nullptr) i gdy próbuje użyć komparatora do wstawiania drugiego elementu, swoje wywala kod.

Trzeba tylko użyć funktor zamiast wskaźnika funkcji

struct compareCounts 
{ 
    bool operator()(const pair<string, size_t> &lhs, 
        const pair<string, size_t> &rhs) const 
    { 
     return lhs.second > rhs.second; 
    } 
}; 

set <pair<string, size_t>, compareCounts> sorted_counter; 
+0

Ah! I właśnie uświadomiłem sobie, że to jest moje pytanie! – EMiller

+2

@ User7391, tj. Powiedziałeś mu * typ * komparatora, ale nigdy tak naprawdę * nie podarował * go. – WhozCraig

+0

@ User7391 Uwaga na próbce dodatkowej Praetorian, informując ją o typie (funktor) może (i robi) użyć instancji tego typu dla eval poprzez 'operator()'. Zwykle jest również preferowany w przypadku wydajności, ponieważ jest * wysoce * prawdopodobne, że jest wbudowany. Gdybym był tobą, użyłbym jego przykładu funktora. – WhozCraig

Powiązane problemy