2012-05-29 30 views
9

Duplicar posibles:
Implementing comparision operators via 'tuple' and 'tie', a good idea?utilizando make_tuple para la comparación

veces tengo que escribir algunas palabras funcionales feas
por ejemplo,

lhs.date_ < rhs.date_ || 
lhs.date_ == rhs.date_ && lhs.time_ < rhs.time_ || 
lhs.date_ == rhs.date_ && lhs.time_ == rhs.time_ && lhs.id_ < rhs.id_ ..... 

realmente me molestó.
Así que empecé a evitar que la escritura siguiente:

std::make_tuple(lhs.date_, lhs.time_, lhs.id_) < 
    std::make_tuple(rhs.date_, rhs.time_, rhs.id_); 

y soy casi feliz, pero cuenta que probablemente estoy usando tuplas no por su propósito hace que me preocupe.

¿Podría criticar esta solución?
¿O es una buena práctica?
¿Cómo se evitan esas comparaciones?

ACTUALIZACIÓN:
Gracias por señalar el std :: lazo para evitar copiar objetos.
Y gracias por señalar en cuestión duplicado

+8

'std :: make_tuple' hace copias de los objetos que pasa (a menos que use' std :: ref' o 'std :: cref') - para comparar objetos existentes _sin hacer copias, use' std :: forward_as_tuple' o 'std :: tie' en lugar de' std :: make_tuple'. – ildjarn

+1

Si usa std :: tie en su lugar, es una muy buena práctica, hace que el operador

Respuesta

12

La declaración de std::tuple operadores de comparación establece que:

Compara izda y dcha lexicográfico, es decir, compara los primeros elementos, si son equivalentes, compara la los segundos elementos, si son equivalentes, compara los terceros elementos, y así sucesivamente.

Lo que está haciendo, además de tener la posibilidad de crear temporarios innecesarios (probablemente optimizados), me parece bien.

Tenga en cuenta que equivalente significa !(lhs < rhs) && !(rhs < lhs) y no lhs == rhs, que es la igualdad . Asumiendo equivalente y igualdad significa lo mismo para su clase, esto estaría bien. Tenga en cuenta que esto no es diferente de, por ejemplo, acceder a un set/map por clave.

Con el fin de evitar los provisionales, puede utilizar std::tie que hace una tupla de referencias lvalue a sus argumentos:

std::tie(lhs.date_, lhs.time_, lhs.id_) < 
    std::tie(rhs.date_, rhs.time_, rhs.id_); 

De manera similar, std::forward_as_tuple hace una tupla de rvalue referencia.

+0

IIRC "equivalente" significa <= && > =. Entonces existe ese riesgo con la tupla, pero probablemente sea seguro en la situación del PO. – djechlin

+0

@djechlin: _equivalent_ significa '! (Lhs

+0

Gracias. Entonces OP debería saber que esto no es lo mismo que lo que estaba haciendo usando ==. No sé cómo se implementa la clase de fecha de OP, pero es concebible para mí que == iría a la fecha y < or > a la segunda. – djechlin

0

Puede ser mejor que use el enlace en lugar de make_tuple (dependiendo de si vale la pena evitar copiar/mover los miembros), pero de lo contrario, esto funcionará, y no hay nada terrible al respecto.

Si lo piensas bien, muchas estructuras POD son básicamente "tuplas con nombre", y C++ de hecho atiende a eso al ofrecer comparación de igualdad por miembros (y copiar, mover, etc.) - y en la mayoría de los casos, extenderlo a (lexicográfico) por miembros menos que la comparación también tiene sentido. Pero desafortunadamente, C++ no proporciona ninguna forma de especificar la comparación lexicográfica de los miembros, salvo que se escriba de forma explícita. En un lenguaje con introspección, por supuesto, sería bastante fácil de agregar, pero en C++, no lo es.

Una respuesta obvia es hacer que tu clase sea realmente una tupla nombrada. En lugar de tener miembros int date_, int64_t time_ y string id_, heredar de tupla y escribir métodos de acceso que oculten la tupla de los usuarios. Pero en este caso, acabas de cambiar la fealdad en las implementaciones de comparación por la fealdad en las implementaciones de acceso, y no está claro que sea mejor.

Usted podría utilizar macros para concluir la fealdad, pero esto probablemente no es mucho mejor:

DEFINE_NAMED_TUPLE_CLASS(MyDate, int date, int64_t time, string id) 
    ... 
END_NAMED_TUPLE_CLASS 

O usted podría construir su propio generador de código externo que permite preprocesar un C extendida ++ que tiene una "named_tuple_class", que maneja simplemente cambiando la etiqueta a "clase" y luego definiendo los operadores de comparación. Pero eso es mucho trabajo.

Cuestiones relacionadas