PDA

Visualizza la versione completa : [C++] Errore su struct "Type no matching function for call to..."


Neptune
18-12-2010, 23:21
Salve a tutti,
ho il seguente metodo di una classe:



template<class K, class E>
void hash_table<K,E>::insert(const mypair<const K, E>& the_pair)
{
// search the table for a matching element
int b = search(the_pair.first);
// chack if matching element found
if (table[b] == NULL){
// no matching element and table not full
table[b] = new mypair< const K, E > (the_pair);
dsize++;
} else {
// check id duplicate or table full
if (table[b]->first == the_pair.first)
// duplicate, change table[b]->second
table[b]->second = the_pair.second;
else{
// table is full
// throw the exception hash_table_full();
}
}
}



nella seguente riga fa riferimento alla struct mypair:


table[b] = new mypair< const K, E > (the_pair)


La struttura la seguente:



template<class K, class E>
struct mypair {
// data member
K first;
E second;

// methods
mypair(){}
mypair(mypair<const K,E>& the_pair){
first = the_pair.first;
second = the_pair.second;
}
};


Il compilatore per mi da errore dicendomi:


Type no matching function for call to 'mypair<const std::basic_string<char>, std::basic_string<char> >::mypair(const mypair<const std::basic_string<char>, std::basic_string<char> >&)' hash_table.h /Dizionari_2 line 184 C/C++ Problem

Non riesco a capire cos' che no gli va a genio. Ho provato anche a cambiare la riga incriminata del metodo in:



table[b] = new mypair< const K, E > (& the_pair)


Ma nulla, da sempre lo stesso errore. Sapreste dirmi in cosa sbaglio? perch ci sto impazzendo da ore.

Vi ringrazio in anticipo,
Neptune.

Neptune
19-12-2010, 00:19
Nel caso servisse l'intero codice lo trovate qui:
http://www.ideone.com/hmlQw

E l'errore che segnala ideone.com questo:


prog.cpp: In member function void hash_table<K, E>::insert(const mypair<const K, E>&) [with K = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, E = int]:
prog.cpp:245: instantiated from here
prog.cpp:222: error: no matching function for call to mypair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>::mypair(const mypair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>&)
prog.cpp:12: note: candidates are: mypair<K, E>::mypair(mypair<const K, E>&) [with K = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, E = int]
prog.cpp:11: note: mypair<K, E>::mypair() [with K = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, E = int]

MItaly
19-12-2010, 01:05
Secondo me hai fatto qualche casino con i cosnt. In generale non ha molto senso specificare dovunque nel parametro K di mypair che la stringa costante, dato che comunque dovr essere inizializzata. Togli quella roba e vedi se funziona.

Neptune
19-12-2010, 01:22
Originariamente inviato da MItaly
Secondo me hai fatto qualche casino con i cosnt. In generale non ha molto senso specificare dovunque nel parametro K di mypair che la stringa costante, dato che comunque dovr essere inizializzata. Togli quella roba e vedi se funziona.

E' che una specifica del professore, vabb, ma dici di cancellare qualsiasi const esistente o solo relativi a quella funzione? :stordita:

Vabb faccio un p di prove.

MItaly
19-12-2010, 01:36
No, non fraintendermi, il const buono e giusto, che secondo me lo devi lasciare stare per quanto riguarda il parametro template della struct.

Neptune
19-12-2010, 01:52
Originariamente inviato da MItaly
No, non fraintendermi, il const buono e giusto, che secondo me lo devi lasciare stare per quanto riguarda il parametro template della struct.

Ho tolto tutti quelli riguardanti quella funzione, ovvero il necessario per farlo compilare, ora il compile va ma se tento di eseguirlo crasha.

Ho provato a mettercelo tutto su ideone.com:

http://www.ideone.com/hgl1Q

e mi da i seguenti errori:



/home/aLq6T8/ccSpDBXf.o:(.rodata._ZTV10hash_tableISsiE[vtable for hash_table<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>]+0x24): undefined reference to `hash_table<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>::erase(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/home/aLq6T8/ccSpDBXf.o:(.rodata._ZTV10hash_tableISsiE[vtable for hash_table<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>]+0x28): undefined reference to `hash_table<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>::modify(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int const&)'
collect2: ld returned 1 exit status


A questo punto cos'altro che lo fa impazzire? il mio compilatore manco ne segnala errori! (eclipse + mingw)

Neptune
19-12-2010, 01:54
Ah no, anche eclipse me lo da lo stesso errore, anche se non era in bella vista :fagiano:

Neptune
19-12-2010, 14:40
Leggendo meglio errore mi ero accorto che semplicemente c'erano dei metodi che venivano solo dichiarati nella classe ma non venivano mai implementati, che codice carino :zizi:

Ora ho un codice che funziona, ma su una funzione da me fatta vorrei essere sicuro che fa esattamente ci che io voglio e non solo un caso fortuito.

Detto in poche parole il costruttore della classe alloca dinamicamente un vettore di puntatori a tipo strutturato (mypair se vede il cocie non altro che una struttura di due elementi chiave e valore, ovvero first e second) in questo modo:



hash_table<K,E>::hash_table(int the_divisor)
{
divisor = the_divisor;
dsize = 0;

table = new mypair<K, E>* [divisor];
for (int i=0; i<divisor; i++)
table[i] = NULL;
}


Ed inizializza tutti i puntatori a NULL

L'inserimento di un nuovo elemento invece, senza scendere di tutte le precondizioni non fa altro che far puntare un elemento del vettore ad un nuovo elemento the_pair.



template<class K, class E>
void hash_table<K,E>::insert(mypair<K, E>& the_pair)
{
// search the table for a matching element
int b = search(the_pair.first);
// chack if matching element found
if (table[b] == NULL){
// no matching element and table not full
table[b] = new mypair<K, E >(the_pair);
dsize++;
} else {
// check id duplicate or table full
if (table[b]->first == the_pair.first)
// duplicate, change table[b]->second
table[b]->second = the_pair.second;
else{
// table is full
// throw the exception hash_table_full();
}
}
}



Ora il mio arduo (:D) compito stato quello di sviluppare la funzione di erase, che si fatta:



template<class K, class E>
void hash_table<K,E>::erase(const K& k)
{
if( find(k) != NULL)
{
// search the table for a matching element
int b = search(k);
delete find(k);
table[b] = NULL;
}

}


Il dubbio questo, la funzione di cancellazione non fa altro che vedere se l'elemento che vuoi cancellare effettivamente esiste con la prima condizione, se esiste ne cerca la posizione nella tabella (si lo so non molto ottimizzato questo codice), dealloca (con delete) la coppia mypair (che ti ritorna da find) e poi setta a NULL il puntatore nella tabella.

E' tutto giusto cos?

Cio se io mettessi solo a null il puntatore sulla tabella ma non mettessi quel delete rimarebbe allocato il mio spazio di memoria no?

La funzione find questa:



template<class K, class E>
mypair<K, E>* hash_table<K,E>::find(const K& the_key)
{
// search the table
int b = search(the_key);
// see if a match was found at table[b]
if (table[b] == NULL || table[b]->first != the_key)
return NULL; // no match
return table[b]; // matching pair
}


Ovvero non dovrebbe far altro che ritornare, nel caso esiste il puntatore proprio all'indirizzo della coppia mypair.

Dite che giusto? con i puntatori non si mai sicuri al 100% :D

Neptune
19-12-2010, 14:47
leggevo un p i commenti sparsi qua e la in inglese riguardo la cancellazione:



DELETION
*
* The deletion of a pair must leave behind a table on which the search method works correctly.
* A deletion may require us to move several pairs. The search for pairs to move begins just after
* the bucket vacated by the deleted pair and proceeds to successive buckets until we either
* reach an empty bucket or we return to the bucket from which the deletion took place.
* When pairs are moved up the table following a deletion, we must take care not to move a pair
* to a position before its home bucket because making such a pair move would cause the search
* for this pair to fail.
*
* An alternative to this method is to introduce the fieled never_used in each bucket. When the
* table is initialized, this field is set to true for all buckets. When a pair is placed into a
* bucket, its never_used field is set to false. Now condition (2) for search termination is
* replaced by: a bucket with its never_used field equal to true is reached. We accomplish a
* removal by setting the table position occupied by the removed pair to NULL. A new pair
* may be inserted into the first empty bucket encountered during a search that begins at the
* pair's home bucket. Notice that in this alternative scheme, never_used is never reset to
* true. After a while all buckets have this field equal to false, and unsuccessful searches
* examines all buckets. To improve performance, we must reorganize the table when many empty
* buckets have their never_used field equal to false. This reorganization could, for example,
* involve reinserting all remaining pairs into an empty hash table.


Sar forse il mio scarso inglese ma qui dice che non posso "cancellare e basta" un elemento ma devo ricompattare in un qualche modo? :fagiano:

MItaly
19-12-2010, 16:00
Originariamente inviato da Neptune
Ora il mio arduo (:D) compito stato quello di sviluppare la funzione di erase, che si fatta:



template<class K, class E>
void hash_table<K,E>::erase(const K& k)
{
if( find(k) != NULL)
{
// search the table for a matching element
int b = search(k);
delete find(k);
table[b] = NULL;
}

}


Il dubbio questo, la funzione di cancellazione non fa altro che vedere se l'elemento che vuoi cancellare effettivamente esiste con la prima condizione, se esiste ne cerca la posizione nella tabella (si lo so non molto ottimizzato questo codice), dealloca (con delete) la coppia mypair (che ti ritorna da find) e poi setta a NULL il puntatore nella tabella.

E' tutto giusto cos?

Cio se io mettessi solo a null il puntatore sulla tabella ma non mettessi quel delete rimarebbe allocato il mio spazio di memoria no?
Esatto. Forse per dovresti anche decrementare dsize, visto che quando inserisci un elemento lo incrementi.



La funzione find questa:



template<class K, class E>
mypair<K, E>* hash_table<K,E>::find(const K& the_key)
{
// search the table
int b = search(the_key);
// see if a match was found at table[b]
if (table[b] == NULL || table[b]->first != the_key)
return NULL; // no match
return table[b]; // matching pair
}


Ovvero non dovrebbe far altro che ritornare, nel caso esiste il puntatore proprio all'indirizzo della coppia mypair.

Dite che giusto? con i puntatori non si mai sicuri al 100% :D
Dovrebbe essere giusto.

Loading