usar una tabla programacion principales lenguaje las invoca implementan funciones funcion estandar como características basicas c++ templates constexpr

una - funciones principales del lenguaje c++



¿Por qué llamar a una función constexpr con una matriz miembro no es una expresión constante? (3)

Tengo la siguiente función auxiliar:

template<typename T, std::size_t N> constexpr std::size_t Length(const T(&)[N]) { return N; }

Lo que devuelve la longitud de una matriz estática. En el pasado esto siempre ha funcionado, pero cuando hago esto:

struct Foo { unsigned int temp1[3]; void Bar() { constexpr std::size_t t = Length(temp1); // Error here } };

Recibo un error al utilizar MSVS 2017:

error C2131: expression did not evaluate to a constant note: failure was caused by a read of a variable outside its lifetime note: see usage of ''this''

Esperaba que alguien pudiera arrojar luz sobre lo que estoy haciendo mal.


MSVC es correcto. Length(temp1) no es una expresión constante. Desde [expr.const]p2

Una expresión e es una expresión constante central, a menos que la evaluación de e , siguiendo las reglas de la máquina abstracta, evalúe una de las siguientes expresiones:

  • this , excepto en una función constexpr o un constructor constexpr que se está evaluando como parte de e ;

temp1 evalúa this implícitamente (porque te estás refiriendo a this->temp1 ), y por lo tanto no tienes una expresión constante. gcc y clang lo aceptan porque admiten VLA como una extensión (intente compilar con -Werror=vla o -pedantic-errors ).

¿Por qué no está permitido? Bueno, podrías acceder a los elementos subyacentes y modificarlos potencialmente. Esto está completamente bien si está tratando con una matriz constexpr o una matriz que se está evaluando como una expresión constante, pero si no lo está, entonces no es posible tener una expresión constante ya que estará manipulando valores que se configuran en el tiempo de ejecución .


Su pregunta ya ha sido respondida, pero en términos de cómo "arreglarla", una manera rápida y sucia es reemplazar

Length(temp1)

con

Length(*(true ? NULL : &temp1))

que creo que es un comportamiento técnicamente indefinido, pero prácticamente va a funcionar bien para MSVC.

Si necesita una solución que funcione a pesar de la UB, puede cambiar la Length para usar un puntero:

template<typename T, std::size_t N> constexpr std::size_t Length(const T(*)[N]) { return N; }

y luego puedes usar Length(true ? NULL : &temp1) .


Length(decltype(temp1){})

parece funcionar

Desafortunadamente, no puedo comentar, pero la solución de Mehrdad es incorrecta. La razón: no es un comportamiento técnicamente indefinido, pero es un comportamiento indefinido. Durante la evaluación de constexpr, el compilador debe detectar un comportamiento indefinido. Por lo tanto, el código está mal formado .