Estoy tratando de calcular la longitud de una cadena literal en tiempo de compilación. Para hacerlo, estoy usando el siguiente código:
#include <cstdio>
int constexpr length(const char* str)
{
return *str ? 1 + length(str + 1) : 0;
}
int main()
{
printf("%d %d", length("abcd"), length("abcdefgh"));
}
Todo funciona como se esperaba, el programa imprime 4 y 8. El código ensamblador generado por clang muestra que los resultados se calculan en tiempo de compilación:
0x100000f5e: leaq 0x35(%rip), %rdi ; "%d %d"
0x100000f65: movl $0x4, %esi
0x100000f6a: movl $0x8, %edx
0x100000f6f: xorl %eax, %eax
0x100000f71: callq 0x100000f7a ; symbol stub for: printf
Mi pregunta: ¿está garantizado por el estándar que la length
función se evaluará en tiempo de compilación?
Si esto es cierto, la puerta para los cálculos de literales de cadena en tiempo de compilación se me acaba de abrir ... por ejemplo, puedo calcular hashes en tiempo de compilación y muchos más ...
<cstdio>
y luego llamar::printf
no es portátil. El estándar solo requiere<cstdio>
proporcionarstd::printf
.printf
puede llevar a una cantidad significativamente menor de código para tratar.Respuestas:
No se garantiza que las expresiones constantes se evalúen en tiempo de compilación, solo tenemos una cita no normativa del borrador de la sección estándar de C ++
5.19
Expresiones constantes que dice esto:Puede asignar el resultado a la
constexpr
variable para asegurarse de que se evalúe en el momento de la compilación, podemos ver esto en la referencia de C ++ 11 de Bjarne Stroustrup que dice (el énfasis es mío ):Por ejemplo:
Bjarne Stroustrup ofrece un resumen de cuándo podemos asegurar la evaluación del tiempo de compilación en esta entrada del blog de isocpp y dice:
Entonces, esto describe dos casos en los que debe evaluarse en el momento de la compilación:
shall be ... converted constant expression
oshall be ... constant expression
, como un límite de matriz.constexpr
como describo anteriormente.fuente
constexpr int x = 5;
, observar que no requiere el valor en tiempo de compilación (asumiendo que no se usa como parámetro de plantilla o cualquier otra cosa) y en realidad emite código que calcula el valor inicial en tiempo de ejecución utilizando 5 valores inmediatos de 1 y 4 operaciones de suma. Un ejemplo más realista: el compilador podría alcanzar un límite de recursividad y aplazar el cálculo hasta el tiempo de ejecución. A menos que haga algo que obligue al compilador a utilizar realmente el valor, "garantizado para ser evaluado en tiempo de compilación" es un problema de QOI.constexpr
cálculo por pura maldad. Incluso es gratis esperar 1 segundo por personaje en una línea de fuente determinada, o tomar una línea de fuente determinada y usarla para sembrar una posición de ajedrez, luego jugar en ambos lados para determinar quién ganó.Es realmente fácil averiguar si una llamada a una
constexpr
función da como resultado una expresión constante central o simplemente se está optimizando:Úselo en un contexto donde se requiera una expresión constante.
fuente
-pedantic
, si usas gcc. De lo contrario, no recibirá advertencias ni erroresenum { Whatever = length("str") }
?static_assert(length("str") == 3, "");
constexpr auto test = /*...*/;
es probablemente el más general y sencillo.Solo una nota, que los compiladores modernos (como gcc-4.x) hacen
strlen
para los literales de cadena en tiempo de compilación porque normalmente se define como una función intrínseca . Sin optimizaciones habilitadas. Aunque el resultado no es una constante de tiempo de compilación.P.ej:
Resultados en:
fuente
strlen
es una función incorporada, si la usamos-fno-builtins
vuelve a llamarla en tiempo de ejecución,strlen
esconstexpr
para mí, incluso con-fno-nonansi-builtins
(parece que-fno-builtins
ya no existe en g ++). Digo "constexpr", porque puedo hacer estotemplate<int> void foo();
yfoo<strlen("hi")>();
g ++ - 4.8.4Permítanme proponer otra función que calcula la longitud de una cadena en tiempo de compilación sin ser recursiva.
Eche un vistazo a este código de muestra en ideone .
fuente
char temp[256]; sprintf(temp, "%u", 2); if(1 != length(temp)) printf("Your solution doesn't work");
ideone.com/IfKUHVNo hay garantía de que una
constexpr
función se evalúe en tiempo de compilación, aunque cualquier compilador razonable lo hará con los niveles de optimización adecuados habilitados. Por otro lado, los parámetros de la plantilla deben evaluarse en tiempo de compilación.Usé el siguiente truco para forzar la evaluación en tiempo de compilación. Desafortunadamente, solo funciona con valores integrales (es decir, no con valores de coma flotante).
Ahora, si escribes
puede estar seguro de que la
if
declaración es una constante en tiempo de compilación sin sobrecarga de tiempo de ejecución.fuente
len
que de todosconstexpr
modoslength
debe ser evaluado en tiempo de compilación.if
condición (donde era esencial que el compilador eliminara el código muerto) para la que originalmente usé el truco.Una breve explicación de la entrada de Wikipedia sobre expresiones constantes generalizadas :
Tener la
constexpr
palabra clave antes de la definición de una función indica al compilador que verifique si se cumplen estas limitaciones. Si es así, y la función se llama con una constante, se garantiza que el valor devuelto es constante y, por lo tanto, se puede usar en cualquier lugar donde se requiera una expresión constante.fuente