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:
#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
).