Las Plantillas de C++ – La Guía Completa, 2ª Edición introduce la max plantilla:

template<typename T>
T max (T a, T b)
{
  //if b < a then yield a else yield b
  return  b < a ? a : b;
}

Y se explica mediante “b < a ? a : b” en lugar de “a < b ? b : a”:

Tenga en cuenta que la (max) de la plantilla de acuerdo a [StepanovNotes]
intencionalmente devuelve «b < a ? r : b» en lugar de «a < b ? b:» a
asegúrese de que la función se comporta correctamente, incluso si los dos valores son
equivalente, pero no es igual.

Cómo entender «even if the two values are equivalent but not equal.«? “a < b ? b : a” parece tener el mismo resultado para mí.

  • Se ve mal a mí… Ambas respuestas son «correctos», pero si a y b son equivalente, a continuación, !(a < b) && !(b < a) es cierto, así que a < b y b < a son falsas, por lo que en b < a ? a : b, b se devuelve, que no es lo que quieres… quieres a < b ? b : a.
  • Usted a menudo puede distinguir entre el equivalente a y b con std::addressof et. al.
  • Si usted a = max(a, b); (repetida) es posible que no desee reemplazar a innecesariamente.
  • Por CIERTO, esta plantilla debe tomar parámetros const-referencias y volver por la const-referencia, de lo contrario, usted está haciendo un montón de inútiles copias (y va a reemplazar a con una copia de a).
  • La canónica tipo que tiene tanto la equivalencia y la igualdad es el CaseInsensitiveString. Para ese tipo, ni un<a ni<a. Pero std::addressof es irrelevante. De hecho, para el T max(T a, T b) ya sabemos addressof(a) != addressof(b).
  • ah, yo estaba pensando en std::max, no se dio cuenta el valor de la plantilla
  • Usted puede referirse a la Stepano v Notas sobre la Programación para más detalles I twitter acerca de esto después de leer que debido a que la explicación no era lo suficientemente detallada.
  • Hilarante. Cómo muchos programadores de c++ se tarda en escribir el max función? Tal vez deberían hacer dos funciones maxFirstIfEqual y maxSecondIfEqual para hacerlo aún más risible.

InformationsquelleAutor Nan Xiao | 2018-06-13

3 Comentarios

  1. 152

    std::max(a, b) es, de hecho, se especifica para volver a cuando las dos son equivalentes.

    Que se considera un error por Stepanov y otros, porque rompe la propiedad útil que dado a y b, siempre se puede ordenar con {min(a, b), max(a, b)}; para que, te gustaría max(a, b) para volver b cuando los argumentos son equivalentes.

    • Desde el enlace que «es difícil para mí para culpar a la gente que lo hace: después de todo, ellos sólo siguen el estándar de C++ especificación de max escrito por mí. Me tomó varios años para ver que estaba equivocado.» – wow!
    • no puedes simplemente hacer {min(a, b), max(b, a)}?
    • Sí, pero todavía es menos evidente. Yo diría que tiene un sentido lógico que max(a,b) devolverá un si-y-sólo-si min(a,b) devuelve b, y viceversa, de modo que son el reverso de cada uno de los otros y la (desordenada) establecer {min(a,b), max(a,b)} es siempre igual a {a,b}.
    • usted ha mencionado desordenada, pero me refería ordenó debido a que en la respuesta de T. C. menciona que «se rompe la propiedad útil que […] siempre se puede ordenar con {min(a, b), max(a, b)}«
    • Sí, lo entendí. ¿Usted no cree que la propiedad mencioné hace más sentido que una implementación sin? A mí max(a, b) y min(a, b) siempre debe devolver respuestas diferentes.
    • Sí, creo que es bonito, pero mi comentario original que venía de un lugar de incertidumbre, no el sarcasmo 🙂 Entonces yo estaba tratando de entender por qué mencionar usted desordenada establece cuando el ejemplo es una lista ordenada. (Ahora entiendo que significaba que el «el (desordenada) set de {min(a,b), max(a,b)}«)
    • Lo siento, has entendido mi comentario como una forma de pensar que estás siendo sarcástico. Que no era mi intención, pero en lugar de explicar por qué la propiedad es lógico desde otro punto de vista. Si usted sigue el enlace para el papel de Stephanov, usted verá que él en realidad le da un ejemplo diferente que el T. C. dio y la manera como lo pongo 🙂
    • Podría agregar la palabra «estable», tal vez? Todavía puedes ordenar (sin la palabra «estable») ellos muy bien si std::max es lo que es: si las dos son equivalentes, están correctamente ordenados no importa que uno es el primero y el que se llega al último.
    • Cualquier orden es fina, haciendo a, b en a, a no lo es.
    • Cómo es que no está bien si a es equivalente a b? Si no son totalmente intercambiables, no debería ser igual. Me suena que el problema es con el diseño de los contenidos de a y b, no con max o min.
    • Si uno, por ejemplo, es la de ordenar una lista de eventos por el tiempo, uno no necesita preocuparse acerca de si la operación de ordenación es estable a la atención acerca de la necesidad de cada evento que aparece exactamente una vez en la entrada, igualmente aparece exactamente una vez en la salida. Ciertas operaciones (como la búsqueda y eliminación de duplicados eventos) puede requerir el uso de una de completar el pedido, pero en muchos otros casos, puede ser aceptable para la lista de eventos simultáneos en orden arbitrario, pero que no se dupliquen o a omitir.
    • La aplicación de min y max a nada, pero de la marca de tiempo (el de la clave de ordenación) en ese escenario no tiene sentido. Los eventos (los objetos) sí no debería ser comparable si la igualdad no implica la intercambiabilidad. La única manera de {min(a, b), max(a, b)} hace alguna sentido como una especie de mecanismo es si los objetos son intercambiables.

  2. 63

    Esta respuesta se explica por qué el código está mal desde un estándar de C++ punto de vista, pero está fuera de contexto.

    Ver @T. C. la respuesta de para una explicación contextual.


    El estándar define std::max(a, b) como sigue [alg.min.max] (el énfasis es mío):

    template<class T> constexpr const T& max(const T& a, const T& b);

    Requiere: Tipo T es LessThanComparable (Tabla 18).

    Devuelve: El valor más grande.

    Observaciones: Devuelve el primer argumento cuando los argumentos son equivalentes.

    Equivalente aquí significa que !(a < b) && !(b < a) es true [alg.clasificación#7].

    En particular, si a y b son equivalentes, tanto a < b y b < a son false, por lo que el valor de la derecha de : será devuelto en el operador condicional, por lo que a tiene que ser a la derecha, así:

    a < b ? b : a

    …parece ser la respuesta correcta. Esta es la versión utilizada por libstdc++ y libc++.

    Por lo que la información en su cotización parece mal de acuerdo a los estándares actuales, pero el contexto en el que se define podría ser diferente.

    • Godbolt enlace que explica el problema (gracias @songyuanyao para la definición de X).
    • He editado la respuesta para especificar que el razonamiento de los objetivos de la norma actual.
    • Yo estaba realmente se refiere a la «Si definimos equiv(a, b) como !comp(a, b) && !comp(b, a)». He cambiado el enlace a una mejor cotización (3 líneas más abajo en el estándar… ).
    • Sorprende que nadie haya mencionado punto flotante, donde a<b y b<a pueden ser ambas falsas porque están desordenadas (uno o ambos NaN, por lo que == es falso también). Que podría ser visto como una especie de equivalencia. débilmente relacionados: x86 del maxsd a, b instrucción implementa a = max(b,a) = b < a ? a : b. (¿Cuál es la instrucción que da sucursales FP min y max en x86?). La instrucción mantiene el operando origen (la 2) en desordenada, por lo que un bucle a través de una matriz se dará NaN si había algún Nan. Pero max_seen = max(max_seen, a[i]) ignorará Nan.
    • Véase también Stepanov Notas sobre la Programación
  3. 21

    El punto es que uno debe ser devuelto cuando son equivalentes; std::max tiene que volver a (es decir, el primer argumento) para este caso.

    Si son equivalentes, devuelve a.

    Así a < b ? b : a debe ser utilizado; por otro lado, b < a ? a : b; volverá b incorrectamente.

    (Como @Holt dijo, la cita parece opuesto.)

    «los dos valores son equivalentes, pero no es igual» significa que tienen el mismo valor cuando se compara, pero migth ser objetos diferentes en otros aspectos.

    por ejemplo,

    struct X { int a; int b; };
    bool operator< (X lhs, X rhs) { return lhs.a < rhs.a; }
    X x1 {0, 1};
    X x2 {0, 2};
    auto x3 = std::max(x1, x2); //it's guaranteed that an X which cantains {0, 1} is returned
    • Por favor podría elaborar sobre por qué std::max(a, b) tiene que volver a, si a y b son equivalentes?
    • href=»https://timsong-cpp.github.io/cppwp/n4659/alg.min.max#11″ >Es sólo una elección arbitraria en el estándar de la parte. Aunque es un poco discutible si es uno bueno.
    • Es sólo a mí o es que esta en contradicción con la pregunta? Si a y b son equivalentes, entonces !(a < b) && !(b < a) es cierto, así que a < b y b < a son falsos, entonces… ?
    • Supongo que la norma sólo quiere determinar; cuando son equivalentes y que uno debe ser devuelto.
    • gracias para refrescar mi memoria sobre el por qué de un objeto sería «equivalente», pero no «iguales».

Dejar respuesta

Please enter your comment!
Please enter your name here