En las funciones constexpr de C ++ 11, una segunda declaración como una assert()
no es posible. A static_assert()
está bien, pero no funcionaría si la función se llama como función 'normal'. El operador de coma podría venir a ayudar a wrto. el assert()
, pero es feo y algunas herramientas escupen advertencias al respecto.
Considere tal 'getter' que es perfectamente comprensible al lado de la afirmación. Pero me gustaría mantener algún tipo de afirmación para el tiempo de ejecución y el tiempo de compilación, pero no puedo sobrecargarlo dependiendo del contexto 'constexpr'.
template<int Size>
struct Array {
int m_vals[Size];
constexpr const int& getElement( int idx ) const
{
ASSERT( idx < Size ); // a no-go for constexpr funcs in c++11
// not possible, even in constexpr calls as being pointed out, but what I would like:
static_assert( idx < Size, "out-of-bounds" );
return m_vals[idx];
}
};
Condiciones secundarias: C ++ 11, sin montón, sin excepciones, sin detalles del compilador.
Tenga en cuenta que los comentaristas señalaron (¡gracias!), static_assert
Sobre el argumento no es posible (pero sería bueno). El compilador me dio un error diferente en el acceso fuera de límites en esa situación.
static_assert
dependienteidx
en absoluto. Solo puede diagnosticar un valor incorrecto deidx
si la función se usa en un contexto que requiere una expresión constante, al forzar la evaluación de una construcción que la convierte en una expresión no constante. Fuera de dicho contexto, nunca puede verificar el valor en tiempo de compilación.Respuestas:
Algo como
Dará un error en tiempo de compilación en caso de fallo de aserción si se usa en un contexto que requiere una expresión constante (porque llamará a una no
constexpr
función).De lo contrario, fallará en tiempo de ejecución con una llamada a
assert
(o su análogo).Esto es lo mejor que puedes hacer hasta donde yo sé. No hay forma de usar el valor de
idx
forzar una verificación en tiempo de compilación fuera del contexto que requiere expresiones constantes.La sintaxis del operador de coma no es agradable, pero las
constexpr
funciones de C ++ 11 son muy limitadas.Por supuesto, como ya notó, el comportamiento indefinido se diagnosticará de todos modos si la función se usa en un contexto que requiere una expresión constante.
Si sabe que
assert
(o su análogo) no se expande a nada que esté prohibido en una expresión constante si la condición se evalúatrue
pero lo hace si se evalúa afalse
, entonces puede usarlo directamente en lugar demy_assert
omitir la indirección que construyo en mi códigofuente
(void)0
por qué en elNDEBUG
caso yvoid()
en el otro? ¿O es realmente lo mismo?(void)0
es un no-op, que compila a nada (que es lo que quiere cuandoNDEBUG
se define), mientras que se necesita elvoid()
fin de que el segundo y tercer operandos del operador condicional tienen el mismo tipo,void
.(void)0
que también estaría bien en todos los casos. Acabo de reemplazarlo en el primer caso, porquevoid()
también se puede analizar como tipo de función sin parámetros y sin tipo de retorno según el contexto. No se puede analizar de esa manera en las subexpresiones en el segundo caso.Mejor que una expresión de coma, puede usar un condicional ternario. El primer operando es su predicado de aserción, el segundo operando es su expresión de éxito, y dado que el tercer operando puede ser cualquier expresión, incluso una no utilizable en un contexto constante de C ++ 11, puede usar una lambda para invocar las
ASSERT
instalaciones de su biblioteca :Explicación del cuerpo de la lambda:
ASSERT(false && (pred))
es para asegurarse de que su maquinaria de aserción se invoque con una expresión apropiada (para la stringificación).struct nxg { nxg() {} } nxg
es para seguridad futura, para garantizar que si compila en C ++ 17 o superior conNDEBUG
lambda todavía noconstexpr
lo es, por lo que la afirmación se aplica en el contexto de evaluación constante.return (success)
está ahí por dos razones: para asegurarse de que el segundo y tercer operandos tengan el mismo tipo, y de modo que si su biblioteca respetaNDEBUG
lasuccess
expresión se devuelva independientementepred
. (pred
se evaluará , pero es de esperar que los predicados de afirmación sean baratos de evaluar y no tengan efectos secundarios).Ejemplo de uso:
fuente
[&]
/[&] -> decltype((success))
para conservar referencias.pred
evaluación debería ser barata, pero no siempre es así. Entonces, comoASSERT_EXPR
macro general , no lo recomendaría. A veces hago llamadas costosas en una afirmación (por ejemplo, para verificar invariantes).NDEBUG
para deshabilitar las afirmaciones de tiempo de ejecución, aún desea que se verifiquen las afirmaciones en tiempo de compilación. Hacer que el cuerpo del caso de falla lambda noconstexpr
sea una forma de garantizar esto, pero tiene el costo de evaluar y descartar el predicado en tiempo de ejecuciónNDEBUG
. De lo contrario, podría definir la macro enNDEBUG
justoreturn (success);
.static_assert
No se puede usar aquí. El argumento de unaconstexpr
función no está permitido en una expresión constante. Por lo tanto, no hay solución a su problema bajo las restricciones dadas.Sin embargo, podemos resolver el problema doblando dos restricciones
no usar
static_assert
(use otros métodos para producir un diagnóstico en tiempo de compilación), yno tenga en cuenta que el operador de coma "es feo y algunas herramientas escupen advertencias al respecto". (Mostrar su fealdad es una desafortunada consecuencia de los estrictos requisitos de las
constexpr
funciones de C ++ 11 )Entonces, podemos usar un normal
assert
:En un contexto de evaluación constante, esto emitirá un error de compilación como
error: call to non-'constexpr' function 'void __assert_fail(const char*, const char*, unsigned int, const char*)'
.fuente
Esto es lo que funciona para mí para la mayoría de los compiladores: https://godbolt.org/z/4nT2ub
Ahora
static_assert
es obsoleto yaconstexpr
que no puede contener un comportamiento indefinido. Entonces, cuando buscas el compilador de índice de matriz informa el error adecuado. Vea aquí .El problema es
assert
. Es una macro cuya implementación no está definida. Si el compilador utiliza una función que no es unaconstexpr
, fallará, pero como puede ver, 3 compiladores principales no tienen ningún problema con eso.fuente
C++11
esto falla solo en gcc godbolt.org/z/DB2zL3/std:c++11
bandera en absoluto y Clang permite el código, aunque requiere C ++ 14. Add-pedantic-errors
and Clang dará los errores adecuados que un compilador puro de C ++ 11 daría.c ++ 11 no puede ser tan ...
idx
constante o nosería bueno si tuviera una función cada una.
Podría ser algo así si se fuerza en una función
fuente
idx
esconst
. Si esto es solo una propuesta estándar de C ++, entonces no veo cómo pertenece en la sección de respuestas.