que initialize and c++ c++11 initializer-list constexpr

c++ - and - static_assert en initializer_list:: size()



difference between const and constexpr in c++ (4)

De mi discusión con @Evgeny, me di cuenta de que esto simplemente funciona (con gcc 4.8 c++11 ) y también puedo hacer la verificación de tamaño al aceptar solo un tamaño compatible en la lista de inicializadores (en la página main ).

(enlace del código: http://coliru.stacked-crooked.com/a/746e0ae99c518cd6 )

#include<array> template<class T, int Length> class Point { public: Point(std::array<T, Length> init) { //not needed// static_assert(init.size() == Length, "Wrong number of dimensions"); } }; int main() { Point<int, 3> q({1,2,3}); //ok // Point<int, 3> q2({1,2,3,4}); //compile error (good!) Point<int, 3> q2({1,2}); // ok, compiles, same as {1,2,0}, feature? return 0; }

¿Por qué no se permite el tamaño std :: initializer_list <_E> :: en static_assert, a pesar de que se declara como constexpr en mi libstdc ++ (v. 4.6)?

Por ejemplo, el siguiente código:

template<class T, int Length> class Point { public: Point(std::initializer_list<T> init) { static_assert(init.size() == Length, "Wrong number of dimensions"); } }; int main() { Point<int, 3> q({1,2,3}); return 0; }

da el siguiente error:

test.C: In constructor ‘Point<T, Length>::Point(std::initializer_list<_Tp>) [with T = int, int Length = 3]’: test.C:60:26: instantiated from here test.C:54:7: error: non-constant condition for static assertion test.C:54:73: in constexpr expansion of ‘init.std::initializer_list<_E>::size [with _E = int, std::initializer_list<_E>::size_type = long unsigned int]()’ test.C:54:7: error: ‘init’ is not a constant expression

Tenga en cuenta que esto funciona bien para un ejemplo trivial:

class A { public: constexpr int size() { return 5; } }; int main() { A a; static_assert(a.size() == 4, "oh no!"); return 0; }


El compilador dice que init es el problema, no init.size ().

Supongo que se podría llamar al constructor desde diferentes lugares con inicializadores de diferente longitud.

(Para más detalles: está intentando escribir un static_assert que depende del valor en tiempo de ejecución de la variable init , es decir, cuántos elementos tiene. static_assert s debe ser evaluable en el momento en que se compila la función. Su código es análogo a este ejemplo trivialmente inválido :)

void foo(int i) { static_assert(i == 42, ""); } int main() { foo(42); } // but what if there''s a caller in another translation unit?


Las "listas de inicialización" son simplemente errores horribles.

No hagas

#include <initializer_list> template<typename T> void Dont(std::initializer_list<T> list) { // Bad! static_assert(list.size() == 3, "Exactly three elements are required."); } void Test() { Dont({1,2,3}); }

Hacer:

template<typename T, std::size_t N> void Do(const T(&list)[N]) { // Good! static_assert(N == 3, "Exactly three elements are required."); } void Test() { Do({1,2,3}); }


Utilice la siguiente sintaxis:

DEMO EN VIVO

#include <initializer_list> template<class T, int Length> class Point { std::initializer_list<T> data; public: constexpr Point(std::initializer_list<T> init) : data ( init.size() == Length ? init : throw 0 ) {} }; int main() { constexpr Point<int, 3> a{{1,2,3}}; constexpr Point<int, 2> b{{1,2,3}}; // compile time error }

Consulte la siguiente SO .

EDIT: interesante que funciona en GCC 4.8.1, pero no funciona en Clang 3.4. Tal vez esto esté relacionado con constexpr de .size() (afaik, en C ++ 14 es constexpr ).