c++ max c++11 min constexpr

c++ - std:: max() y std:: min() no constexpr



c++11 (5)

Me acabo de dar cuenta de que el nuevo estándar define min(a,b) y max(a,b) sin constexpr .

Ejemplos de 25.4.7, [alg.min.max]:

template<class T> const T& min(const T& a, const T& b); template<class T> T min(initializer_list<T> t);

¿No es esto una pena? Me hubiera gustado escribir

char data[ max(sizeof(A),sizeof(B)) ];

en lugar de

char data[ sizeof(A) > sizeof(B) ? sizeof(A) : sizeof(B) ]; char data[ MAX(sizeof(A),sizeof(B)) ]; // using a macro

¿Alguna razón por la cual esos no pueden ser constexpr ?


Actualización crítica

El siguiente análisis es incorrecto, porque confunde una cosa importante . La siguiente declaración que hice omitió un detalle importante, que requiere una respuesta completamente diferente.

Los retornos max referencia sin nombre se referirán a ese operando.

El problema aquí es que la sustitución de invocación de función se realiza en ese punto. Si la confirmación de invocación incluiría la conversión lvalor a rvalue en ese glvalue que max yields, todo estaría bien, porque la lectura de un glvalue que se refiere a una duración de almacenamiento temporal no estática está bien durante el cálculo de la expresión constante . Pero dado que la lectura ocurre fuera de la sustitución de invocación de función, el resultado de la sustitución de invocación de función es un valor l . El texto respectivo de la especificación dice

Una expresión de constante de referencia es una expresión constante de núcleo lvalue que designa un objeto con una duración de almacenamiento estático o una función.

Pero la referencia que devuelve max produce un lvalue que designa un objeto de duración de almacenamiento no especificado. Se requiere la sustitución de invocación de función para producir una expresión constante , no simplemente una expresión constante central . Por lo tanto max(sizeof(A), sizeof(B)) no se garantiza que funcione max(sizeof(A), sizeof(B)) .

El siguiente texto (más antiguo) debe leerse teniendo en cuenta lo anterior .

No veo ninguna razón en este momento por la cual no quieras poner un constexpr allí. De todos modos, el siguiente código definitivamente es útil

template<typename T> constexpr T const& max(T const& a, T const& b) { return a > b ? a : b; }

Al contrario de lo que escriben otras respuestas, creo que esto es legal. No todas las instancias de max deben ser funciones constexpr. El n3242 actual dice

Si la especialización de plantilla instanciada de una plantilla de función constexpr o función miembro de una plantilla de clase no satisface los requisitos para una función constexpr o constexpr constructor, esa especialización no es una función constexpr o constexpr constructor.

Si llama a la plantilla, la deducción de argumento producirá una especialización de plantilla de función. Llamarlo activará la sustitución de invocación de función . Considera la siguiente llamada

int a[max(sizeof(A), sizeof(B))];

En primer lugar, realizará una conversión implícita de los dos prismáticos size_t a los dos parámetros de referencia, vinculando ambas referencias a objetos temporales que almacenan su valor. El resultado de esta conversión es un glvalue para cada caso que se refiere a un objeto temporal (ver 4p3). Ahora la sustitución de invocación de función toma esos dos glvalues ​​y sustituye todas las ocurrencias de b en el cuerpo de la función por esos glvalues

return (<glval.a>) > (<glval.b>) ? (<glval.a>) : (<glval.b>);

La condición requerirá lvalue para validar las conversiones en estos glvalues, que son permitidos por 5.19p2

  • un glvalue de tipo literal que se refiere a un objeto temporal no volátil inicializado con una expresión constante

La expresión condicional arrojará un glvalue al primer o segundo operando. Los retornos max referencia sin nombre se referirán a ese operando. Y la conversión final de lvalue a rvalue que ocurre en la especificación de tamaño de dimensión de matriz será válida por la misma regla mencionada anteriormente.

Tenga en cuenta que initializer_list actualmente no tiene funciones integradas. Esta es una limitación conocida y se manejará después de C ++ 0x, lo más probable es que constexpr esos miembros constexpr .


La inclusión de constexpr versiones constexpr de std::min() y std::max() en C ++ 14 demuestra que no hay ningún obstáculo fundamental para hacer (versiones de) estas funciones constexpr . Parece que esto no se consideró lo suficientemente temprano cuando se agregó constexpr a C ++ 11.

Obviamente, para las versiones donde se proporciona una función de comparación, esa función debe ser constexpr para que la expansión de la plantilla constexpr éxito.


Mi suposición es que, en el caso general, el operador <(T, T) tampoco garantiza que sea constexto.


std :: min y std :: max son constexpr en C ++ 14, lo que obviamente significa que no hay una buena razón (en estos días) para no tenerlos constexpr. Problema resuelto :-)


min y max son solo expresiones constantes si las llamas con expresiones constantes como argumentos. Como se supone que son mucho más utilizables que eso, no puedes hacer la declaración.

constexpr es lo que Wikipedia dice sobre constexpr (énfasis agregado). Sé que Wikipedia no es la referencia definitiva, pero creo que es correcto en este caso.

El uso de constexpr en una función impone limitaciones muy estrictas sobre lo que puede hacer esa función. Primero, la función debe tener un tipo de devolución no nulo. En segundo lugar, los contenidos de la función deben ser de la forma: return expr. En tercer lugar, expr debe ser una expresión constante, después de la sustitución del argumento. Esta expresión constante solo puede llamar a otras funciones definidas como constexpr, o puede usar otras variables de datos de expresión constante.