2011-04-16 14 views
8

Me pregunto, porque los literales predefinidos como ULL, f, etc. obviamente se resuelven en tiempo de compilación. No parece que la estándar (2.14.8 [lex.ext]) para definir esto, pero parece que tienden hacia el tiempo de ejecución:¿Los literales definidos por el usuario se resuelven en tiempo de compilación o en tiempo de ejecución?

[2.14.8/2]
A definida por el usuario-literal se trata como una llamada al, un operador literal o plantilla de operador literal (13.5.8). A determine la forma de esta llamada para un literal definido por el usuario L con ud-sufijo X, literal-operador-id cuyo identificador de sufijo literal es X se busca en el contexto de L usando las reglas para nombre no calificado búsqueda (3.4.1). Deje S ser el conjunto de declaraciones encontradas por esta búsqueda. S no estará vacío.
(el énfasis es mío.)

Sin embargo, para mí esto parece introducir innecesaria en tiempo de ejecución por encima, como literales sólo pueden ser añadidos a los valores que están disponibles en tiempo de compilación de todos modos como 13.37f o "hello"_x (donde _x es un literal definido por el usuario).
Luego, tenemos la plantilla definida por el usuario literal, que nunca se define realmente en la norma AFAICS (es decir, no se da ningún ejemplo, por favor, demuéstrame que estoy equivocado). ¿Es esa función de alguna manera invocada mágicamente en tiempo de compilación o todavía es tiempo de ejecución?

Respuesta

6

Sí, recibe una llamada a función. Pero las llamadas a funciones pueden ser expresiones de constante de tiempo de compilación debido a las funciones de operador literales constexpr.

Para ver un ejemplo, vea this one. Como otro ejemplo para mostrar la forma avanzada de constexpr cálculos permitidos por el FDIS, para tener tiempo de compilación de bases 26 literales que puede hacer

typedef unsigned long long ull; 

constexpr ull base26(char const *s, ull ps) { 
    return (*s && !(*s >= 'a' && *s <= 'z')) ? throw "bad char!" : 
    (!*s ? ps : base26(s + 1, (ps * 26ULL) + (*s - 'a'))); 
} 

constexpr ull operator "" _26(char const *s, std::size_t len) { 
    return base26(s, 0); 
} 

Decir "bcd-"_26 evaluará un saque de banda expresión, y por lo tanto hacer que el valor de retorno de convertirse en no constante. A su vez, hace que cualquier uso de "bcd-"_26 como expresión constante se vuelva mal formado, y cualquier uso no constante para lanzar en tiempo de ejecución. El formulario permitido "bcd"_26 se evalúa como una expresión constante del valor calculado respectivo.

Tenga en cuenta que la lectura de cadenas de literales no está explícitamente permitida por el FDIS, sin embargo no presenta ningún problema y GCC lo admite (la referencia de caracteres lvalue es una expresión constante y el valor del carácter se conoce en tiempo de compilación). OMI, si uno entrecierra los ojos, uno puede leer el FDIS como si esto estuviera permitido.

Entonces, tenemos la plantilla definida por el literal usuario, que nunca se mete define en las AFAICS estándar (es decir, no se da ningún ejemplo, por favor me demostrar que estaba equivocado)

El tratamiento de los literales como la invocación de plantillas de operador literales se define en 2.14.8. Encontrará más ejemplos en 13.5.8 que detallan las funciones/plantillas de funciones del operador en sí.

¿Esa función de alguna manera se invoca mágicamente en tiempo de compilación o sigue siendo el tiempo de ejecución?

La palabra clave es sustitución de invocación de función. Ver 7.1.5.

+0

Gracias, me olvidé por completo de 'constexpr'. :) Y también gracias por ese párrafo. – Xeo

+0

Buscar la terminación NUL parece sospechoso cuando le han entregado la longitud. –

0

@Johannes S es correcto, por supuesto, pero desea añadir claramente (ya que enfrentado a este), que incluso para los literales definidos constexpr de usuario, los parámetros no se consideran constexpr o compilar constante de tiempo, por ejemplo en el sentido de que no se pueden usar como constantes enteras para plantillas.

Además, sólo cosas como esta realidad darán evaluación en tiempo de compilación:

inline constexpr long long _xx(unsigned long long v) { 
    return (v > 100) ? throw std::exception() : v; 
} 
constexpr auto a= 150_xx; 

lo tanto, que no se compilará. Pero esta voluntad:

cout << 150_xx << endl; 

y la siguiente no está permitido:

inline constexpr long long _xx(unsigned long long v) { 
    return some_trait<v>::value; 
} 

Eso es molesto, pero natural, teniendo en cuenta que (otros) constexpr funciones se pueden llamar también durante la ejecución.

Sólo para los literales definidos por el usuario enteros es posible a la fuerza en tiempo de compilación procesamiento, mediante el uso de la forma de la plantilla. Ejemplos en mi pregunta y respuesta propia: https://stackoverflow.com/a/13869688/1149664

Cuestiones relacionadas