and c++ c++17 constexpr

c++ - and - inicio constexpr de un std:: array



constexpr in c++ (1)

Tengo problemas para entender por qué tanto gcc-8.2.0 como clang-7.0.0 rechazan el siguiente código (código en vivo here ):

#include <array> int main() { constexpr std::array<int,3> v{1,2,3}; constexpr auto b = v.begin(); // error: not a constexpr return 0; }

con el error

error: ''(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)'' is not a constant expression (constexpr auto b = v.begin();)

De acuerdo con en.cppreference.com , la función de miembro begin() se declara constexpr . ¿Es este un error de compilación?


Así que vamos a evitar std::array para hacer esto un poco más fácil:

template <typename T, size_t N> struct array { T elems[N]; constexpr T const* begin() const { return elems; } }; void foo() { constexpr array<int,3> v{{1, 2, 3}}; constexpr auto b = v.begin(); // error } constexpr array<int, 3> global_v{{1, 2, 3}}; constexpr auto global_b = global_v.begin(); // ok

¿Por qué es b un error pero global_b está bien? Del mismo modo, ¿por qué b pondría bien si static constexpr que v es static constexpr ? El problema es fundamentalmente sobre los punteros. Para tener una expresión constante que sea un puntero, tiene que apuntar a una cosa conocida, constante, siempre. Eso realmente no funciona para las variables locales sin la duración del almacenamiento estático, ya que tienen una dirección fundamentalmente mutable. Pero para las estadísticas locales o globales de función, tienen una dirección constante, por lo que puede apuntarles un puntero constante.

En standardese, desde [expr.const]/6 :

Una expresión constante es una expresión constante de glvalue core que se refiere a una entidad que es un resultado permitido de una expresión constante (como se define a continuación), o una expresión de constante prvalue core cuyo valor satisface las siguientes restricciones:

  • si el valor es un objeto de tipo de clase, [...]
  • si el valor es de tipo puntero, contiene la dirección de un objeto con duración de almacenamiento estático , la dirección más allá del final de dicho objeto ([expr.add]), la dirección de una función o un valor de puntero nulo, y
  • [...]

b no es ninguna de esas cosas en la segunda bala, así que esto falla. Pero global_b satisface la condición en negrita, como lo haría b si v fuera declarada static .