c++ - pueden - porque no puedo seguir hashtag en instagram
¿Por qué no son constexpr std:: algorithms y cuál podría ser? (5)
Este es el tema de la propuesta de Antony Polukhin P0202:
Agregar modificadores Constexpr a funciones en y encabezados
que espero sea adoptado por el Grupo de Trabajo de Evolución de la Biblioteca C ++ y llegue a C ++ 20.
¿Por qué no son constexpr
métodos std::algorithm
? Si entiendo las nuevas reglas de C ++ 14 correctamente, muchos de estos métodos podrían ser constexpr
. Por ejemplo, ¿por qué no se puede std::find
ser constexpr
?
static constexpr std::array<char, 4> DnaBases {''A'', ''C'', ''G'', ''T''};
constexpr bool is_dna(char b)
{
return std::find(std::cbegin(DnaBases), std::cend(DnaBases), b) != std::cend(DnaBases); // why not?
}
¿Qué otro std::algorithm
s podría ser constexpr
?
La biblioteca estándar actual (C ++ 14) está bastante constexpr
respecto a las capacidades correspondientes del lenguaje central con respecto a constexpr
.
Por ejemplo, MSVC 2015, que solo tiene soporte de lenguaje C ++ 11 para constexpr
, podría implementar casi por completo el uso completo de la biblioteca estándar de C ++ 14 de constexpr
. Las únicas excepciones fueron std::min
, std::max
, std::minmax
, std::min_element
, std::max_element
, std::minmax_element
para std::initializer_list
.
A partir de C ++ 1z (17?), std::xxx_element
algoritmos std::xxx_element
se convertirán en algoritmos constexpr
para iterador general y entradas de comparador para unificar el uso de std::initializer_list
. Además, hay propuestas para funciones constexpr
lambda para C ++ 1z también.
Con la actualización de las lambdas, aún quedan algunas limitaciones básicas del lenguaje para evitar que todo el encabezado <algorithm>
convierta en constexpr
. (Tenga en cuenta que estos no son obstáculos tecnológicos fundamentales, la mayoría de ellos podrían resolverse permitiendo que el compilador los evalúe).
- Algunos algoritmos pueden asignar dinámicamente memoria llamando a
std::get_temporary_buffer
(std::inplace_merge
,std::stable_sort
ystd::stable_partition
) que no está permitido en contextosconstexpr
. - Algunos algoritmos pueden recurrir a rutinas de C de bajo nivel como
memset
(std::fill
ystd::fill_n
) que evitarían que los autores de bibliotecas usen estos algoritmos en contextosconstexpr
. - Algunas implementaciones de algoritmos pueden beneficiarse del uso juicioso de
goto
(por ejemplo,std::nth_element
,std::stable_sort
), para lo cual se rechazó una propuesta deC++1z
. - Por último, pero no menos importante,
constexpr
es un cambio de interfaz, que promete que todas las implementaciones futuras tendrán que cumplir esta promesa. Por ese motivo, las implementaciones no pueden agregarconstexpr
como una característica de Calidad de implementación (en contraste connoexcept
).
Especialmente el 4to problema detiene la experimentación de cuánto se podría constexpr
para la biblioteca estándar (algoritmos, contenedores y otras utilidades). En su lugar, se debe escribir y aprobar una propuesta por separado para cada expansión de constexpr
.
Las funciones no pueden sobrecargarse en base a constexpr
. Como resultado, cualquier función definida como constexpr
debe implementarse en una forma que pueda ser un constexpr
. Este requisito impone restricciones en todas las implementaciones.
La especificación de C ++ 14 es algo relajada con respecto a las restricciones en comparación con C ++ 11. Sin embargo, cuando se finalizó la especificación, nadie confiaba en que todas las optimizaciones que se pueden lograr sin la restricción constexpr
se pueden lograr cuando los algoritmos tienen la obligación de ser constexpr
. Sin saber que la funcionalidad no constexpr
no se ve obstaculizada por el mandato de implementaciones constexpr
, los algoritmos no se definirán como constexpr
. Se constexpr
uso no constexpr
de algoritmos es el uso principal de los algoritmos.
Puede valer la pena tener un conjunto especial de algoritmos que se definen como constexpr
. No estoy al tanto de una propuesta correspondiente. Tampoco veo mucho si la demanda justifica la estandarización, pero mi percepción puede ser diferente de la de otros.
Puede ser constexpr
, pero no puede evaluarse como una expresión constante, ya que en este caso, por ejemplo, para la búsqueda en tiempo de compilación se requiere que: begin/end
sea constexpr, el * operator
del iterador sea constexpr, operator ==
debe ser constexpr, operator !=
para el iterador debe ser constexpr, operator ++
para el iterador debe ser constexpr. Pero, si todas las funciones son constexpr
, entonces muchos algoritmos se pueden implementar con constexpr
.
Puede consultar la biblioteca SPROUT para la implementación de contenedores / algoritmos constexpr.
Y charla relacionada en los foros de isocpp.org
std::algorithm
algoritmo actúan sobre los iteradores. Hay una razón técnica por la que hacerlos constexpr
generalmente evitaría la compilación (en C ++ 11) o no haría nada (en C ++ 14 o con constexpr
condicional), pero también hay una razón semántica por la que no sería posible. sentido para ellos ser constexpr
.
La razón técnica es que constexpr
funciones constexpr
no pueden llamar expresiones no constexpr
. ForEveR señala que las funciones constexpr
plantilla no pueden evaluarse en tiempo de compilación si llaman expresiones no constexpr
.
En el caso de std::algorithm
, la evaluación de constexpr
funciones constexpr
en std::algorithm
requerirá que las funciones para acceder a los iteradores de contenedores sean constexpr
, lo que a su vez requeriría que los iteradores mismos sean tipos constexpr
. Pero esto es imposible casi por definición; los contenedores normalmente se diseñan como un acceso ligero a la memoria asignada en el montón, pero la memoria del montón no se puede asignar en tiempo de compilación (por supuesto). En los comentarios a continuación, dyp señala que los iteradores no siempre apuntan a los contenedores, pero es improbable que incluso estos iteradores puedan usarse en tiempo de compilación; por ejemplo, los objetos de flujo no son legibles ni grabables en el momento de la compilación, ya que IO no se puede realizar en el momento de la compilación.
Esto lleva al problema semántico: constexpr
semánticamente significa que una función está destinada a ser posible evaluar en tiempo de compilación. Declarar funciones condicionalmente constexpr
cuando es imposible evaluarlas en tiempo de compilación haría que la API fuera confusa y engañosa.
Ahora, creo que el lenguaje se mejoraría si hubiera una forma de crear y usar contenedores en tiempo de compilación; Esto haría que constexpr
mucho más similar a las capacidades macro de Lisp. Eventualmente, esto puede agregarse, pero actualmente no es realmente compatible con el código de biblioteca estándar existente. El enfoque más flexible, de permitir que algunos objetos vivan en el montón durante el tiempo de compilación , es, como se mencionó anteriormente, no está soportado en absoluto por el lenguaje central, y crearía algunas complicaciones graves. Por ejemplo, ¿qué sería legal hacer con tales objetos? O bien sus vidas tendrían que limitarse solo al tiempo de compilación, o deberían incluirse como memoria estática const en el programa final (como un literal de cadena), o ... ¿qué?