Dada una función muy trivial,
int transform(int val) {
return (val + 7) / 8;
}
Debería ser muy obvio que es fácil convertir esta función en una constexpr
función, lo que me permite usarla al definir constexpr
variables, así:
constexpr int transform(int val) {
return (val + 7) / 8;
}
Mi suposición es que esto es estrictamente una mejora, ya que la función todavía se puede llamar en un constexpr
contexto diferente, y ahora también se puede usar para ayudar a definir variables constantes de tiempo de compilación.
Mi pregunta es, ¿hay situaciones en las que esta sea una mala idea? Por ejemplo, al hacer esta función constexpr
, ¿puedo encontrarme en una situación en la que esta función ya no sea utilizable en una circunstancia particular, o donde se porte mal?
Respuestas:
Esto solo importa si la función es parte de una interfaz pública y desea mantener versiones futuras de su API compatible con binarios. En ese caso, debe pensar detenidamente cómo desea evolucionar su API y dónde necesita puntos de extensión para futuros cambios.
Eso hace que un
constexpr
calificador sea una decisión de diseño irrevocable. No puede eliminar este calificador sin un cambio incompatible en su API. También limita cómo puede implementar esa función, por ejemplo, no podrá realizar ningún registro dentro de esta función. No todas las funciones triviales seguirán siendo triviales en la eternidad.Eso significa que debe usarlo preferiblemente
constexpr
para funciones que son inherentemente funciones puras, y que serían realmente útiles en tiempo de compilación (por ejemplo, para la metaprogramación de plantillas). No sería bueno hacer las funciones constexpr solo porque la implementación actual resulta ser constexpr-able.Cuando la evaluación en tiempo de compilación no sea necesaria, el uso de funciones en línea o funciones con enlace interno parecería más apropiado que eso
constexpr
. Todas estas variantes tienen en común que el cuerpo de la función es "público" y está disponible en la misma unidad de compilación que la ubicación de la llamada.Si la función en cuestión no forma parte de una API pública estable, esto no es un problema, ya que puede cambiar arbitrariamente el diseño a voluntad. Pero como ahora controla todos los sitios de llamadas, no es necesario marcar una función constexpr "por si acaso". Usted sabe si se está utilizando esta función en un contexto constexpr. Agregar calificadores innecesariamente restrictivos podría considerarse ofuscación.
fuente
Marcar una función
constexpr
también la convierte en una función en línea § [dcl.constexpr] / 1:inline
, a su vez, significa que debe incluir la definición de esa función en cada unidad de traducción en la que se pueda utilizar. Eso básicamente significa que lasconstexpr
funciones tienen que ser:La mayoría de las funciones típicas que desea declarar en un encabezado y definir en un archivo fuente (y cualquier otra cosa que las use solo incluye el encabezado, luego los enlaces contra el archivo objeto de esa fuente)
constexpr
simplemente no funcionarán.En teoría, supongo que podría mover todo a los encabezados y tener solo un archivo fuente que solo incluya todos los encabezados, pero esto dañaría drásticamente los tiempos de compilación, y para la mayoría de los proyectos serios requeriría una inmensa cantidad de memoria para compilar.
Una
constexpr
función también está restringida de alguna manera, por lo que para algunas funciones puede no ser una opción en absoluto. Las restricciones incluyen:constexpr
.try
bloque.Me he saltado un par de cosas bastante oscuras (por ejemplo, tampoco puede contener una
goto
o unaasm
declaración), pero entiendes la idea: para bastantes cosas, simplemente no funcionará.En pocas palabras: sí, hay bastantes situaciones en las que esta sería una mala idea.
fuente