PDA

Visualizza la versione completa : [C++] STL: map e key personalizzata


giuseppe500
06-01-2011, 16:10
ciao.
Vorrei creare un indice per una mappa stl che ha due paramentri :
1)shader , un wstring
2)geometry un wstring
ho provato a fare:



class Cidx{
public:
wstring strShader;
wstring strGeometry;
};

std::map<Cidx,wstring>m;

Cidx idx;
idx.strGeometry = L"giugio";
idx.strShader = L"ferrari";

m[idx]= L"test1";

Cidx idx1;
idx1.strGeometry = L"1";
idx1.strShader = L"2";

m[idx1] = L"test2";

wstring str1 = m[idx];
wstring str2 = m[idx1];

idx.strGeometry =L"asdasd";

str1 = m[idx];


ma non va , mi da ques errore:
Error 1 error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : could not deduce template argument for 'const std::_Tree<_Traits> &' from 'const Cidx' C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfunctional 125

come posso risolvere?
grazie.

shodan
06-01-2011, 17:16
Devi aggiungere bool operator < ( const Cidx& ) const alla tua classe in modo che la mappa lo usi per ordinare le chiavi.

giuseppe500
06-01-2011, 17:45
grazie shodan , ho provato cosi:
bool operator < ( const Cidx& ) const{if(strShader < strGeometry)return false;return true;}
dove strShader e strGeometry sono le due variabili della chiave.
ma non va , dove sbaglio ?
e perchè?
grazie.

shodan
06-01-2011, 18:08
In pseudo codice dev'essere:


bool operator < ( const Cidx& rhs) const {
if (variabile_vuoi_confrontare < rhs.variabile_vuoi_confrontare) return true;
return false;
}

Se vuoi confrontare solo strShader, all'interno dell'if metterai:
strShader<rhs.strShader;

se vuoi confrontare solo strGeometry, all'interno dell'if metterai:
strGeometry<rhs.strGeometry

se vuoi confrontare un mix delle variabili dovrai stabilire tu il criterio per ritornare true e false;

giuseppe500
06-01-2011, 18:13
grazie, ho provato a fare un confronto sul mix dei due elementi cosi:


return strcmp((char*)strShader.c_str(),(char*)a.strShader .c_str()) && strcmp((char*)strGeometry.c_str(),(char*)a.strGeom etry.c_str()) < 0;



ho provato un po e sembra che non ci siano errori , se anche una delle due stringhe è diversa non legge niente , se sono uguali entrambe ritorna il valore indicizzato dalle due variabili.

vedi qualcosa di sbagliato?


ciao.

shodan
06-01-2011, 18:23
Tutto. :facepalm:
std::wstring implementa di suo un operatore <di confronto, quindi non hai bisogno di ricorrere a funzioni C per farlo.
Inoltre strcmp confronta char, non wchar_t, pertanto è sbagliata di per se.

Se devi fare un confronto multiplo fallo in maniera naturale.


if ( ( strShader < a.strShader ) && (strGeometry < a.strGeometry ) ) return true;
return false;

giuseppe500
06-01-2011, 18:43
ho fatto un gran casino è vero shodan , ma voglio solo cercare di capire:



std::map<Cidx,wstring>m;

Cidx idx;
idx.strGeometry = L"giugio";
idx.strShader = L"ferrari";

m[idx]= L"test1";

Cidx idx1;
idx1.strGeometry = L"1";
idx1.strShader = L"2";

m[idx1] = L"test2";

wstring str1 = m[idx]; //perfetto
wstring str2 = m[idx1];//perfetto

str1 = L"";
Cidx s2;
s2.strGeometry =L"asdasd";

str1 = m[s2];//sbagliato , non dovrebbe ritornare niente perchè le chiavi mixate
//non sono ambedue le stesse invece ritorna "test2"

Cidx s3;
s3.strGeometry = L"giugio";
s3.strShader = L"2";

str1 = m[s3];//stesso errore

Ho capito i function object , ma non riesco a capire sulle mappe:
tutte le volte che inserisco o leggo un dato viene richiamata la funzione < e in base a questa viene estratto un dato?
ho letto che in c++ esiste il concetto di egualianza e egualita' una per il < e una per l'== che sono due concetti differenti.
ma perchè mi estrae il dato lo stesso anche se una delle due chiavi è diversa?

scusa per il casino mentale ma voglio capire.

ciao

giuseppe500
06-01-2011, 19:47
penso di aver capito:



bool operator < ( const Cidx& a) const
{

if (a.strGeometry != strGeometry)
return a.strGeometry < strGeometry;
else if (a.strShader != strShader)
return a.strShader < strShader;
return false;

}

si chiama strict weak order e si basa su una serie di elementi che tranne il primo e l'ultimo hanno tutti un predecessore ed un successore come il map.
ho messo il != e l'else if per gestire il problema delle chiavi parzialmente uguali.

sbaglio?
ciao,

shodan
06-01-2011, 20:32
E' corretto. In effetti non avevo considerato il caso di uguaglianza.
L'unica modifica che farei io è invertire i vari membri, mettendo a a destra.


if (strGeometry != rhs.strGeometry)
return strGeometry < rhs.strGeometry;
else if (strShader != rhs.strShader)
return strShader < rhs.strShader;
return false;

in modo da evidenziare il concetto di A < B.

Loading