2012-05-24 14 views
7

El STL utiliza el "menor que" como el comparador predeterminado. Una llamada de comparador STL en un objeto envuelto con la referencia_wrapper <>does not compile, incluso si la clase subyacente tiene definido el operador "<".¿Debería std :: reference_wrapper contener el operador de comparación predeterminado "<"?

Parece, esto es porque hay no implicit conversion realizaron en las LHS del LHS.operator < (RHS) cuando se trata de una función miembro. He verificado que using a free version como el comparador funciona.

Sin embargo, si el reference_wrapper proporcionó el operador "<", que llama "<" en el subyacente, se obviará la necesidad de utilizar la función gratuita.

hice la siguiente adición en el código de la reference_wrapper (tomado de VS11 Beta xrefwrap.h), y podrían utilizar std :: mapa con una clase envuelta en mi versión de la reference_wrapper <> que tiene la "<" operador definido.

bool operator <(reference_wrapper<_Ty> const rhs) const { 
    return this->get() < rhs.get(); 
} 

añadió más tarde: Si he entendido bien, reference_wrapper <> proporciona funciones de copia/asignar semántica asociada con las PAD necesarios por muchas bibliotecas, al tiempo que oculta la sintaxis relacionada PTR. Esto permite el uso de sintaxis de tipo de referencia, sin la sobrecarga de copias locales. Para compararlo con ejemplos usando ptrs pierde por completo uno del punto de los wrappers_de referencia: desea evitar el uso de la sintaxis de tipo ptr.

Como están las cosas ahora, el código que funciona directamente en objetos se rompe cuando los objetos se envuelven en wrappers_referencia. Huelga decir que "<" es el comparador predeterminado, de hecho lo hace especial; en un porcentaje significativo del código existente, los objetos los definirán para obviar la necesidad de comparadores especiales.

Agregado más tarde # 2: El historial de esta característica sugiere que evitar el uso de la sintaxis ptr no era el propósito original. Sin embargo, ha pasado una década desde que se introdujo por primera vez en el impulso. Con una gran cantidad de programadores nuevos "guiados" to avoid ptr based syntax (sin duda influenciados por los idiomas libres de ptr), esta función puede ser cada vez más útil si funciona sin problemas, especialmente cuando se trata de almacenar objetos heredados en contenedores STL y copias de valor en todo .

añadió más tarde # 3: Mejora de código heredado con el código mínimo cambia Con el tiempo las clases finas se vuelven pesados ​​y el tamaño de los objetos en los contenedores aumenta. Una forma rápida de mejorar el rendimiento es evitar las copias, a través de objetos envueltos. Esto proporcionará el rendimiento de tipo "C ptr" sin las copias adicionales con cambios mínimos en el código.

std::map<const Object, string> objTable; 
// can be rewritten as to avoid object copies using the 
// __myOwn::reference_wrapper which contains the '<' operator 
std::map<__myOwn::reference_wrapper<const Object>, string> rwTable_myOwn; 

// which works with out any non-member free comparator functions 
rwTable_myOwn[a]="One"; // Compiles and works 

// When using the table with the std::reference_wrapper 
std::map<std::reference_wrapper<const Object>, string> rwTable_std; 
//the map does not work 
rwTable_std[a]="One"; // Fails to compile it needs the custom non-member comparator 
+0

@GManNickG VSOverFlow

+0

No, 'reference_wrapper' no se creó para sustituir a los punteros. Se entiende como un reemplazo para las referencias (de ahí el nombre). –

+0

Thx para los orígenes; @Xeo también lo señaló (ver respuesta a continuación). http://stackoverflow.com/a/9149473/1408646 sugiere que hay un elemento de estilo cuando se trata de evitar la sintaxis ptr. – VSOverFlow

Respuesta

9

No, no debería. No es tarea de reference_wrapper hacer otra cosa que envolver como referencia como valor.

Si es necesario comparar dos reference_wrapper<T> 's (que es no una referencia a T), entonces es su trabajo para asegurarse de que el trabajo.Por el mismo motivo, std::set<T*> no define de manera predeterminada la comparación como std::less<T>(*x, *y), ni tampoco su caso. El contenedor es solo un puntero no nulo.

¿Por qué detenerse en un único operador de comparación o en todos los operadores de comparación? ¿Por qué no sobrecargar el contenedor de referencia para todas las de las funciones estándar? Porque no vale la pena cuando la solución es tan fácil.

+0

Se reduce a por qué se creó reference_wrapper <> en primer lugar. Por lo que entiendo, es para evitar la sintaxis basada en punteros y atenerse a la sintaxis basada en referencias, al tiempo que permite el uso de bibliotecas existentes que esperan copiar/asignar semántica y evitar copias innecesarias. El ejemplo del conjunto es ortogonal al problema que se está tratando, ya que utiliza explícitamente la sintaxis basada en ptr. La otra pregunta acerca de por qué detenerse en VSOverFlow

+2

@ vsaxena: Creo que 'std :: [c] ref' y' std :: reference_wrapper' (o mejor dicho, sus equivalentes de Boost) fueron creados originalmente para cosas como 'std :: thread',' std :: bind', 'std :: async', etc. que necesitan semántica de valores para los argumentos que se pasan a las funciones, pero el usuario no quiere semántica de valores (es decir, copias). Esto realmente no tiene nada que ver con la semántica de puntero contra referencia, sino más bien con darle al usuario la opción de cómo pasar argumentos sin requerir extrañas trampas por parte del usuario o de la implementación. – Xeo

+3

Imagine si 'reference_wrapper' no existe. Desea 'bind 'argumento' heavy_object a; 'a una función' void f (heavy_object const &) '. Una llamada normal como 'bind (f, a)' creará una copia dentro del objeto 'bind' returns (que es el único valor por defecto razonable). Podría usar 'bind (f, & a)' para almacenar solo un puntero, pero ahora el objeto 'bind' ya no puede llamar' f', ya que 'f' no espera un puntero. No puede almacenar por defecto una referencia al argumento, ya que no tiene forma de hacer un valor de eso, lo que puede sobrevivir al alcance original de los argumentos. – Xeo

Cuestiones relacionadas