c++ - parametros - Comparando cadenas STL que usan diferentes asignadores
parametros para imprimir en 3d (2)
La norma solo define operadores que usan tipos de cadenas homogéneas, es decir, todos los argumentos de la plantilla deben coincidir. Sin embargo, puede definir un operador de igualdad adecuado en el espacio de nombres donde se define el asignador: la búsqueda dependiente del argumento lo encontrará allí. Si elige implementar su propio operador de asignación, se vería algo como esto:
bool operator== (std::string const& s0,
std::basic_string<char, std::char_traits<char>, MyCharAllocator> const& s1) {
return s0.size() == s1.size() && std::equal(s0.begin(), s0.end(), s1.begin()).first;
}
(más algunas otras sobrecargas). Llevando esto al siguiente nivel, incluso puede ser razonable definir las versiones de los diversos operadores relacionales en términos de los requisitos del contenedor y no restringir los argumentos de la plantilla:
namespace my_alloc {
template <typename T> class allocator { ... };
template <typename T0, typename T1>
bool operator== (T0 const& c0, T1 const& c1) {
return c0.size() == c1.size() && std::equal(c0.begin(), c0.end(), c1.end);
}
...
}
Obviamente, los operadores pueden estar restringidos a tipos de contenedores específicos, que difieren solo en sus parámetros de plantilla de asignador.
Con respecto a por qué el estándar no define comparaciones de tipos mixtos, la razón principal detrás de no apoyar la comparación de tipos mixtos es, probablemente, que en realidad no desea mezclar asignadores en su programa en primer lugar. Es decir, si necesita usar un asignador, usaría un tipo de asignador que encapsula una política de asignación polimórfica dinámica y siempre use el tipo de asignador resultante. El razonamiento para esto sería que, de lo contrario, obtendría una interfaz incompatible o tendría que hacer de todo una plantilla, es decir, si desea conservar algún nivel de vocabulario utilizado. Por supuesto, con el uso de un solo tipo de asignador adicional, tendría dos tipos de cadenas de vocabulario: la instanciación predeterminada y la creación de instancias para su asignación especial.
Dicho esto, hay otra razón potencial para no apoyar la comparación de tipo mixto: si el operator==()
realmente se convierte en una comparación entre dos valores, como es el caso si los asignativos difieren, puede dar lugar a una definición mucho más amplia de igualdad de valor : debería std::vector<T>() == std::deque<T>
ser compatible? Si no, ¿por qué la comparación entre cadenas con diferentes asignadores sería especial? Por supuesto, el asignador es un atributo no destacado de std::basic_string<C, T, A>
que podría ser una buena razón para ignorarlo. No estoy seguro de si la comparación de tipo mixto debe ser compatible. Puede ser razonable apoyar a los operadores (esto probablemente se extiende a otros operadores además del operator==()
) para los tipos de contenedores que difieren solo en su tipo de asignador.
Me gustaría comparar cadenas STL que se asignan con diferentes asignadores , por ejemplo, una std::string
ordinaria con una cadena utilizando un asignador STL personalizado . Desafortunadamente, parece que el operator==()
habitual operator==()
no funciona en este caso:
// Custom STL allocator to allocate char''s for string class
typedef MyAllocator<char> MyCharAllocator;
// Define an instance of this allocator
MyCharAllocator myAlloc;
// An STL string with custom allocator
typedef std::basic_string
<
char,
std::char_traits<char>,
MyCharAllocator
>
CustomAllocString;
std::string s1("Hello");
CustomAllocString s2("Hello", myAlloc);
if (s1 == s2) // <--- ERROR: doesn''t compile
...
En particular, MSVC10 (VS2010 SP1) emite el siguiente mensaje de error:
error C2678: binario ''=='': no se ha encontrado ningún operador que tome un operando de la izquierda del tipo ''std :: string'' (o no hay una conversión aceptable)
Entonces, un código de nivel inferior (menos legible) como este:
if (strcmp(s1.c_str(), s2.c_str()) == 0)
...
debería ser usado.
(Esto también es particularmente molesto en los casos en que, por ejemplo, hay std::vector
de cadenas distribuidas de forma diferente, donde la sintaxis simple v[i] == w[j]
habitual no se puede utilizar).
Esto no me parece muy bien, ya que un asignador personalizado cambia la forma en que se solicita la memoria de cadena, pero la interfaz de una clase de cadena (incluida la comparación con operator==()
) es independiente de la forma particular en que una cadena asigna su memoria .
¿Hay algo que me falta aquí? ¿Es posible mantener la interfaz de alto nivel C ++ y las sobrecargas del operador en este caso?
Utilice std::lexicographical_compare
para una comparación menor que:
bool const lt = std::lexicographical_compare(s1.begin(), s1.end(),
s2.begin(), s2.end());
Para la comparación de igualdad puede usar std::equal
:
bool const e = s1.length() == s2.length() &&
std::equal(s1.begin(), s1.end(), s2.begin());
Alternativamente, puede recurrir a strcmp
(o en realidad a memcmp
, ya que tiene la semántica correcta, recuerde que la cadena de C ++ es más general que una cadena C), como sugirió, que potencialmente puede emplear un poco de magia de nivel inferior como comparar una palabra de máquina completa a la vez (aunque el algoritmo anterior también puede estar especializado). Mida y compare, yo diría. Para cadenas cortas, los algoritmos de la biblioteca estándar son al menos muy autodescriptivos.
De acuerdo con la idea de @ Dietmar a continuación, podría incluir esas funciones en una sobrecarga de plantilla:
#include <string>
#include <algorithm>
template <typename TChar,
typename TTraits1, typename TAlloc1,
typename TTraits2, typename TAlloc2>
bool operator==(std::basic_string<TChar, TTraits1, TAlloc1> const & s1,
std::basic_string<TChar, TTraits2, TAlloc2> const & s2)
{
return s1.length() == s2.length() &&
std::equal(s1.begin(), s1.end(), s2.begin());
}
Ejemplo de uso:
#include <ext/malloc_allocator.h>
int main()
{
std::string a("hello");
std::basic_string<char, std::char_traits<char>, __gnu_cxx::malloc_allocator<char>> b("hello");
return a == b;
}
De hecho, podría definir dicha sobrecarga para la mayoría de los contenedores estándar. Incluso podría moldearlo en una plantilla, pero eso sería extremo.