Me parece que tener una "función que siempre devuelve 5" es romper o diluir el significado de "llamar a una función". Debe haber una razón, o una necesidad de esta capacidad o no estaría en C ++ 11. ¿Por qué está ahí?
// preprocessor.
#define MEANING_OF_LIFE 42
// constants:
const int MeaningOfLife = 42;
// constexpr-function:
constexpr int MeaningOfLife () { return 42; }
Me parece que si escribí una función que devuelve un valor literal, y llegué a una revisión de código, alguien me diría, entonces debería declarar un valor constante en lugar de escribir return 5.

constexpr? Si es así, puedo ver un uso.const. De hecho, ¡la intención obligatoria es útil ! Las dimensiones de la matriz son el ejemplo canónico.Respuestas:
Supongamos que hace algo un poco más complicado.
Ahora tiene algo que puede evaluarse hasta una constante, manteniendo una buena legibilidad y permitiendo un procesamiento un poco más complejo que simplemente establecer una constante en un número.
Básicamente proporciona una buena ayuda para la mantenibilidad, ya que se vuelve más obvio lo que está haciendo. Toma
max( a, b )por ejemplo:Es una opción bastante simple, pero significa que si llama
maxcon valores constantes, se calcula explícitamente en tiempo de compilación y no en tiempo de ejecución.Otro buen ejemplo sería una
DegreesToRadiansfunción. Todos encuentran los grados más fáciles de leer que los radianes. Si bien puede saber que 180 grados está en radianes, está mucho más claro escrito de la siguiente manera:Aquí hay mucha información útil:
http://en.cppreference.com/w/cpp/language/constexpr
fuente
Introducción
constexprno se introdujo como una forma de decirle a la implementación que algo se puede evaluar en un contexto que requiere una expresión constante ; Las implementaciones conformes han podido probar esto antes de C ++ 11.Algo que una implementación no puede probar es la intención de un cierto código:
¿Sin qué sería el mundo
constexpr?Digamos que está desarrollando una biblioteca y se da cuenta de que desea poder calcular la suma de cada número entero en el intervalo
(0,N].La falta de intención
Un compilador puede demostrar fácilmente que la función anterior es invocable en una expresión constante si el argumento pasado se conoce durante la traducción; pero no ha declarado esto como una intención, simplemente resultó ser el caso.
Ahora viene alguien más, lee tu función, hace el mismo análisis que el compilador; " ¡Oh, esta función es utilizable en una expresión constante!"y escribe el siguiente fragmento de código.
La optimizacion
Usted, como desarrollador de bibliotecas "impresionante" , decide que
fdebe almacenar en caché el resultado cuando se invoca; ¿Quién querría calcular el mismo conjunto de valores una y otra vez?El resultado
Al presentar su tonta optimización, rompió cada uso de su función que estaba en un contexto donde una expresión constante se requería .
Nunca prometiste que la función fuera utilizable en una expresión constante , y sin ella
constexprno habría forma de proporcionar esa promesa.Entonces, ¿por qué necesitamos
constexpr?El uso principal de constexpr es declarar intención .
Si una entidad no está marcada como
constexpr- nunca fue diseñada para usarse en una expresión constante ; e incluso si es así, confiamos en el compilador para diagnosticar dicho contexto (porque ignora nuestra intención).fuente
constexprexpresiones. En otras palabras, casi cualquier cosa puede ser anotadaconstexpr(¿tal vez algún día simplemente desaparecerá debido a esto?), Y a menos que uno tenga un criterio de cuándo usarlaconstexpro no, casi todo el código se escribirá como tal .I/O,syscallydynamic memory allocationdefinitivamente no se puede marcar comoconstexprAdemás, no todo debería serloconstexpr.constexpres una garantía de algún tipo de comportamiento. Justo como loconsthace.int f (int n) { return n > 0 ? n + f (n-1) : n;} T arr[f(10)];no pueda hacer que se compile en ningún lado?Tome
std::numeric_limits<T>::max(): por cualquier razón, este es un método.constexprSería beneficioso aquí.Otro ejemplo: desea declarar una matriz C (o a
std::array) que es tan grande como otra matriz. La forma de hacer esto en este momento es así:Pero no sería mejor poder escribir:
Gracias a
constexpr, puedes:fuente
constexprobliga al compilador a hacer que la función devuelva un valor de tiempo de compilación (si puede).constexprno se puede usar en una declaración de tamaño de matriz, ni como argumento de plantilla, independientemente de si el resultado de la llamada a la función es una constante de tiempo de compilación o no. Estos dos son básicamente los únicos casos de uso,constexprpero al menos el argumento de caso de uso de plantilla es algo importante.-pedanticopción y se marcará como un error.constexprLas funciones son realmente agradables y una gran adición a C ++. Sin embargo, tiene razón en que la mayoría de los problemas que resuelve pueden solucionarse de manera poco eficiente con macros.Sin embargo, uno de los usos de
constexprno tiene constantes tipeadas equivalentes a C ++ 03.fuente
fourno se resuelve. Realmente tuve que cavar para averiguar quién estaba tomando la dirección de mistatic constvariable.fourtampocofiveestán en el alcance.enum classtipo, corrige algunos de los problemas de enumeración.Por lo que he leído, la necesidad de constexpr proviene de un problema en la metaprogramación. Las clases de rasgos pueden tener constantes representadas como funciones, piense: numeric_limits :: max (). Con constexpr, esos tipos de funciones se pueden usar en la metaprogramación, o como límites de matriz, etc.
Otro ejemplo fuera de mi cabeza sería que para las interfaces de clase, es posible que desee que los tipos derivados definan sus propias constantes para alguna operación.
Editar:
Después de hurgar en SO, parece que otros han encontrado algunos ejemplos de lo que podría ser posible con constexprs.
fuente
constexpres más específicamente útil en un compilador con un poderoso sistema de evaluación de expresiones en tiempo de compilación. C ++ realmente no tiene pares en ese dominio. (eso es un gran elogio para C ++ 11, en mi humilde opinión)Del discurso de Stroustrup en "Going Native 2012":
fuente
Otro uso (aún no mencionado) son los
constexprconstructores. Esto permite crear constantes de tiempo de compilación que no tienen que inicializarse durante el tiempo de ejecución.Empareje eso con literales definidos por el usuario y tendrá soporte completo para clases literales definidas por el usuario.
fuente
Solía haber un patrón con metaprogramación:
Creo que
constexprse introdujo para permitirle escribir tales construcciones sin la necesidad de plantillas y construcciones extrañas con especialización, SFINAE y otras cosas, pero exactamente como escribiría una función de tiempo de ejecución, pero con la garantía de que el resultado se determinará en la compilación -hora.Sin embargo, tenga en cuenta que:
Compila esto
g++ -O3y verás quefact(10)efectivamente se evacua en tiempo de compilación!Un compilador compatible con VLA (por lo tanto, un compilador C en modo C99 o un compilador C ++ con extensiones C99) puede incluso permitirle hacer:
Pero por el momento no es C ++ estándar:
constexprparece una forma de combatir esto (incluso sin VLA, en el caso anterior). Y todavía existe el problema de la necesidad de tener expresiones constantes "formales" como argumentos de plantilla.fuente
std::array<int, fact(2)>y verá que fact () no se evalúa en tiempo de compilación. Es solo el optimizador GCC haciendo un buen trabajo.Acabo de comenzar a cambiar un proyecto a c ++ 11 y encontré una situación perfectamente buena para constexpr que limpia métodos alternativos para realizar la misma operación. El punto clave aquí es que solo puede colocar la función en la declaración de tamaño de matriz cuando se declara constexpr. Hay varias situaciones en las que puedo ver que esto es muy útil para avanzar con el área de código en la que estoy involucrado.
fuente
static inline constexpr const autoProbablemente es mejor.Todas las otras respuestas son geniales, solo quiero dar un ejemplo genial de una cosa que puedes hacer con constexpr que es increíble. See-Phit ( https://github.com/rep-movsd/see-phit/blob/master/seephit.h ) es un motor de análisis y plantillas HTML en tiempo de compilación. Esto significa que puede poner HTML y sacar un árbol que pueda ser manipulado. Hacer el análisis en tiempo de compilación puede brindarle un poco de rendimiento adicional.
Del ejemplo de la página de github:
fuente
Su ejemplo básico sirve el mismo argumento que el de las constantes mismas. Por que usar
terminado
Porque es mucho más fácil de mantener. Usar constexpr es mucho, mucho más rápido de escribir y leer que las técnicas de metaprogramación existentes.
fuente
Puede habilitar algunas nuevas optimizaciones.
consttradicionalmente es una pista para el sistema de tipos, y no se puede utilizar para la optimización (por ejemplo, unaconstfunción miembro puedeconst_castmodificar el objeto de todos modos, legalmente, porconstlo que no se puede confiar para la optimización).constexprsignifica que la expresión es realmente constante, siempre que las entradas a la función sean constantes. Considerar:Si esto se expone en algún otro módulo, el compilador no puede confiar en que
GetNumber()no devolverá valores diferentes cada vez que se lo llame, incluso consecutivamente sin llamadas no constantes en el medio, porqueconstpodría haberse descartado en la implementación. (Obviamente, cualquier programador que hizo esto debería ser fusilado, pero el lenguaje lo permite, por lo tanto, el compilador debe cumplir con las reglas).Agregando
constexpr:El compilador ahora puede aplicar una optimización donde el valor de retorno de
GetNumber()se almacena en caché y eliminar llamadas adicionalesGetNumber(), porqueconstexpres una garantía más sólida de que el valor de retorno no cambiará.fuente
constse puede usar en la optimización ... Es un comportamiento indefinido modificar un valor definido const incluso después de unconst_castIIRC. Esperaría que fuera consistente para lasconstfunciones de los miembros, pero necesitaría verificar eso con el estándar. Esto significaría que el compilador puede hacer optimizaciones de forma segura allí.int xvs.const int x), entonces es seguro modificarloconst_castquitando const en un puntero / referencia a él. Deconst_castlo contrario, siempre invocaría un comportamiento indefinido y sería inútil :) En este caso, el compilador no tiene información sobre la constancia del objeto original, por lo que no puede decirlo.int GetNumber() const = 0;) debería declarar elGetNumber()método virtual. El segundo (constexpr int GetNumber() const = 0;) no es válido porque el especificador puro (= 0) implica que el método es virtual, pero constexpr no debe ser virtual (ref: en.cppreference.com/w/cpp/language/constexpr )Cuando usar
constexpr:fuente
constexprdebería preferirse a las macros de preprocesador oconst.Es útil para algo como
Ate esto con una clase de rasgos o similar y se vuelve bastante útil.
fuente