2012-05-01 8 views
9

Contesto: Sto arrivando dal mondo Java e sono abbastanza nuovo in C++ o Qt.C++ unordered_map fallisce quando viene utilizzato con un vettore come chiave

Per giocare con unordered_map, ho scritto il seguente programma semplice:

#include <QtCore/QCoreApplication> 
#include <QtCore> 
#include <iostream> 
#include <stdio.h> 
#include <string> 
#include <unordered_map> 

using std::string; 
using std::cout; 
using std::endl; 
typedef std::vector<float> floatVector; 

int main(int argc, char *argv[]) { 
    QCoreApplication a(argc, argv); 

    floatVector c(10); 
    floatVector b(10); 

    for (int i = 0; i < 10; i++) { 
     c[i] = i + 1; 
     b[i] = i * 2; 
    } 

    std::unordered_map<floatVector, int> map; 

    map[b] = 135; 
    map[c] = 40; 
    map[c] = 32; 

    std::cout << "b -> " << map[b] << std::endl; 
    std::cout << "c -> " << map[c] << std::endl; 
    std::cout << "Contains? -> " << map.size() << std::endl; 

    return a.exec(); 
} 

Purtroppo, io sono in esecuzione nell'errore folowing che non è entusiasmante. Non c'è nemmeno un numero di linea.

:-1: error: collect2: ld returned 1 exit status

Qualche idea dell'origine del problema?

Grazie in anticipo.

+1

È necessaria una funzione di hash che accetta un 'vector ' –

+2

Questo non è un errore di runtime. –

+0

@SethCarnegie Era quello che pensavo fosse il problema. Tuttavia, mi sembra che una classe di base come vettore debba avere una funzione di hash predefinita. Se non è il caso, potresti spiegarmi come procurarmene uno o indicarmi del materiale. Grazie! –

risposta

21

§23.2.5, comma 3, dice:

Each unordered associative container is parameterized by Key , by a function object type Hash that meets the Hash requirements (17.6.3.4) and acts as a hash function for argument values of type Key , and by a binary predicate Pred that induces an equivalence relation on values of type Key .

Utilizzando vector<float> come Key e non fornire tipi di hash e l'equivalenza predicato espliciti significa il default std::hash<vector<float>> e sarà utilizzato std::equal_to<vector<float>>.

Il std::equal_to per la relazione di equivalenza va bene, perché c'è un operatore == per i vettori, ed è quello che usa std::equal_to.

Tuttavia, non esiste una specializzazione std::hash<vector<float>>, ed è probabilmente quello che dice l'errore del linker che non hai mostrato. È necessario fornire il proprio hash per farlo funzionare.

Un modo semplice di scrivere un tale Hasher è quello di utilizzare boost::hash_range:

template <typename Container> // we can make this generic for any container [1] 
struct container_hash { 
    std::size_t operator()(Container const& c) const { 
     return boost::hash_range(c.begin(), c.end()); 
    } 
}; 

Quindi è possibile utilizzare:

std::unordered_map<floatVector, int, container_hash<floaVector>> map; 

Naturalmente, se avete bisogno di una semantica diversa parità nella mappa è necessario per definire la relazione di hash e di equivalenza in modo appropriato.


1. Tuttavia, evitare questo per hashing contenitori non ordinati, come diversi ordini produrranno diverse hash, e l'ordine in un contenitore non ordinato non è garantita.

+1

Grazie mille per aver risolto il mio problema. Nota per le persone che avrebbero lo stesso problema: per utilizzare boost :: hash_range necessario per #include

+0

@ user1162647: Questa è letteralmente la prima cosa in quella pagina del documento. ; -] – ildjarn

+0

@R.Martinho Fernandes: Se stai ancora guardando, i documenti in quella pagina dicono: "hash_range è sensibile all'ordine degli elementi quindi non sarebbe appropriato utilizzarlo con un contenitore non ordinato". Questo suggerisce che l'utilizzo sopra è sbagliato? – ForeverLearning

Problemi correlati