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_assertSobre 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_assertdependienteidxen absoluto. Solo puede diagnosticar un valor incorrecto deidxsi 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
constexprfunció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
idxforzar 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
constexprfunciones 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úatruepero lo hace si se evalúa afalse, entonces puede usarlo directamente en lugar demy_assertomitir la indirección que construyo en mi códigofuente
(void)0por qué en elNDEBUGcaso yvoid()en el otro? ¿O es realmente lo mismo?(void)0es un no-op, que compila a nada (que es lo que quiere cuandoNDEBUGse define), mientras que se necesita elvoid()fin de que el segundo y tercer operandos del operador condicional tienen el mismo tipo,void.(void)0que 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
ASSERTinstalaciones 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() {} } nxges para seguridad futura, para garantizar que si compila en C ++ 17 o superior conNDEBUGlambda todavía noconstexprlo 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 respetaNDEBUGlasuccessexpresión se devuelva independientementepred. (predse 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.predevaluación debería ser barata, pero no siempre es así. Entonces, comoASSERT_EXPRmacro general , no lo recomendaría. A veces hago llamadas costosas en una afirmación (por ejemplo, para verificar invariantes).NDEBUGpara 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 noconstexprsea 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 enNDEBUGjustoreturn (success);.static_assertNo se puede usar aquí. El argumento de unaconstexprfunció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
constexprfunciones 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_assertes obsoleto yaconstexprque 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++11esto falla solo en gcc godbolt.org/z/DB2zL3/std:c++11bandera en absoluto y Clang permite el código, aunque requiere C ++ 14. Add-pedantic-errorsand Clang dará los errores adecuados que un compilador puro de C ++ 11 daría.c ++ 11 no puede ser tan ...
idxconstante o nosería bueno si tuviera una función cada una.
Podría ser algo así si se fuerza en una función
fuente
idxesconst. Si esto es solo una propuesta estándar de C ++, entonces no veo cómo pertenece en la sección de respuestas.