2010-10-30 21 views
5

Verificar el siguiente código:comparador para STL establece

string toLowerCase(const string& str) { 
    string res(str); 
    int i; 

    for (i = 0; i < (int) res.size(); i++) 
     res[i] = (char) tolower(res[i]); 

    return res; 
} 

class LeagueComparator 
{ 
public: 
    bool operator()(const string& s1, const string& s2) 
    { 
     return toLowerCase(s1) < toLowerCase(s2); 
    } 
}; 

int main() 
{ 
    set<string, LeagueComparator> leagues; 
    set<string, LeagueComparator>::iterator iter; 

    leagues.insert("BLeague"); 
    leagues.insert("aLeague"); // leagues = {"aLeague", "BLeague"} 
    leagues.insert("ALeague"); 

    for (iter = leagues.begin(); iter != leagues.end(); iter++) 
     cout << *iter << endl; 

    return 0; 
} 

La salida es:

aLeague 
BLeague 

que es chocante para mí. Pensé (y esperando) la salida sería:

aLeague 
ALeague 
BLeague 

Antes de la ejecución de leagues.insert("ALeague");, la leagues contiene "aLeague" y "BLeague". Mi pregunta es, al ejecutar leagues.insert("ALeague"); por qué la máquina trata "ALeague" == "aleague"? De acuerdo con mi entendimiento, no existe el elemento "ALeague" en leagues. Por lo tanto, "ALeague" se debe insertar en leagues. El comparador debe determinar dónde poner "ALeague".

Gracias de antemano.

PD: Por favor, no me pegue para usar el molde de estilo C. : P Soy demasiado flojo para escribir static_cast.

+0

El hecho de que se siente que tiene que trabajar para realizar una C++ fundido estilo es uno de los principales razón C moldes estilo ++ existe - es decir, que se debe evitar cualquier tipo de colada en C++. En este caso, debe eliminar los moldes completamente, y usar los tipos correctos en su lugar. Es decir. en lugar de '(int) res.size()', elimine el molde y cambie el tipo de 'i' para que sea' unsigned'. –

+0

Además, 'i' debe declararse en el ciclo, no fuera del ciclo. Y en C++, toLowerCase probablemente debería simplemente llamar a 'std :: transform (str.begin(), str.end(), str.begin(), std :: ptr_fun (tolower))' en lugar de escribir un bucle explícito. –

+0

@Billy ONeal: gracias.necesito ser usado para usar 'transform()'. que 'toLowerCase' fue escrito por mí hace muchos años. Creo que no sabía sobre 'transformar' en ese momento. actualizaré mi base de código. – Donotalo

Respuesta

14

Su comparador, gracias a la toLowerCase, dice que "aLeague" == "ALeague". Dado que (según su comparador) "aLeague" < "ALeague" == false y "ALeague" < "aLeague" == false, deben ser equivalentes. E insertar un elemento equivalente en un conjunto no hace nada.

+3

+1. Tenga en cuenta que el comparador no establece la igualdad, está estableciendo la equivalencia. Hay una diferencia w.r.t. documentación estándar y STL. –

+0

Gracias, editando mi publicación. –

3

Dado el comparador que proporcionó, "ALeague" es de hecho equivalente "unaLiga".

Dados dos valores, x e y, y un menos-que comparador z:

  • Si z (x, y) es verdadera, entonces x es menor que y
  • Si z (y, x) es verdadero, entonces y es menor que x
  • Si ninguno es verdadero, entonces x es equivalente a y
  • Si ambos son verdaderos, entonces usted tiene un comparador roto.
+0

+1, pero leve problema con la tercera viñeta w.r.t. Documentos STL. Hay una distinción entre igualdad y equivalencia. Un comparador menor que no puede establecer la igualdad, solo la equivalencia. –

+0

@Billy ONeal: según el documento STL (no lo tengo), ¿cuáles son las definiciones de "igualdad" y "equivalencia"? – Donotalo

+0

@Donotalo: Igualdad es la comparación usando un comparador de igualdad, o 'operator =='. La equivalencia es el estado donde a menos que el comparador o 'operator <' devuelve falso para cualquier orden de los argumentos, como se especifica aquí. Conceptualmente, es la diferencia entre [igualdad comparable] (http://www.sgi.com/tech/stl/EqualityComparable.html) y [menos que comparable] (http://www.sgi.com/tech/stl/ LessThanComparable.html). –

4

Cuando inserta cualquier valor en un conjunto, el objeto comprueba si ya contiene ese valor. Su objeto LeagueComparator compara ALeague con los otros dos valores que ya están en el conjunto. Determina que el valor existente aLeague no es mayor o menor que la nueva entrada propuesta (ALeague), por lo que deben ser iguales, por lo que no procede con la inserción. El conjunto se queda con solo dos elementos. Ese es el objetivo de proporcionar un objeto de comparación de clientes, para que pueda controlar cómo el conjunto determina si dos elementos coinciden.

+0

+1. Tenga en cuenta que para ser coherente con los documentos STL, la mayoría de los usos de "igual" aquí deberían reemplazarse por "equivalente". Menos que los comparadores no pueden establecer la igualdad. –

0

Reemplazar su LeagueComparator con

class LeagueComparator 
{ 
public: 
    bool operator()(const string& s1, const string& s2) 
    { 
     return toLowerCase(s1) < toLowerCase(s2) || 
       !(toLowerCase(s2) < toLowerCase(s1)) && s1 < s2; 
    } 
}; 
+0

Eso es equivalente a especificar ningún comparador en absoluto. Su comparador simplemente devuelve 's1

+0

No es verdad. 's1 =" b "', 's2 =" A "'. Mi comparador devuelve 'false' debido a' false || ! true && true = false'. 's1