std:: max() y std::min() no constexpr


Acabo de notar 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 una lástima? 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

Cualquier razón por la que los no pueden ser constexpr?

Author: Jeffrey Bosboom, 2011-04-09

5 answers

Actualización crítica

El siguiente análisis es incorrecto, porque confunde una cosa importante. En la siguiente declaración me perdí un detalle importante, que requiere una respuesta completamente diferente.

La referencia sin nombre max devuelve se referirá a ese operando.

El problema aquí es que sustitución de invocación de función es hecho en ese punto. Si la institución de invocación incluiría el lvalue a conversión de rvalue en ese glvalue que max produce, todo estaría bien, porque la lectura de un glvalue que se refiere a un no temporal de duración de almacenamiento estático está bien durante el cálculo de la expresión constante. Pero como 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 lvalue . El texto respectivo de la especificación dice

Una expresión constante de referencia es una constante del núcleo lvalue expresión que designa un objeto con 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 especificada. La sustitución de invocación de función es necesaria para producir una expresión constante , no simplemente una expresión constante core. Así que max(sizeof(A), sizeof(B)) no está garantizado que funcione.

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


No puedo ver ninguna razón en este momento por la que no quiera pegar 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;
}

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

Si la especialización de plantilla instanciada de una plantilla de función constexpr o una función miembro de una plantilla de clase fallaría satisfacer los requisitos para una función constexpr o un constructor constexpr, que la especialización no es una función constexpr o un constructor constexpr.

Si llama a la plantilla, la deducción de argumentos producirá una especialización de plantilla de función. Llamándolo se activará sustitución de invocación de función. Considere la siguiente llamada

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

Primero hará una conversión implícita de los dos size_t prvalues a los dos parámetros de referencia, vinculando ambos 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 a y b en el cuerpo de la función por esos glvalues

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

La condición requerirá conversiones lvalue a rvalue 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 dará un glvalue al primer o segundo operando. La referencia sin nombre max devuelve se referirá 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 citada anteriormente.


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

 13
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-27 16:06:12

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: -)

 13
Author: einpoklum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-07 17:48:02

La inclusión de constexpr versiones 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 tenga éxito.

 1
Author: Toby Speight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-14 08:11:22

min y max son solo expresiones constantes si las llamas con expresiones constantes como argumentos. Dado que están destinados a ser mucho más utilizables en general que eso, no puede hacer la declaración.

Esto es lo que Wikipedia dice sobre constexpr (sin cursiva en el original). Sé que Wikipedia no es la referencia definitiva, pero creo que es correcta en este caso.

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

 -1
Author: Mark Ransom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-09 14:33:11

Mi conjetura es que, en el caso general, operador

 -3
Author: ZeRemz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-09 13:01:55