static assert on initializer list:: size()


¿Por qué no se permite std::initializer_list<_e>::size en un static_assert, aunque esté declarado 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;
}
Author: Morwenn, 2011-03-26

4 answers

El compilador dice que init es el problema, no init.Tamaño().

Supongo que el constructor podría ser llamado desde diferentes lugares con diferentes inicializadores de longitud.

(Para elaborar: Estás tratando de 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 tienen que ser evaluables 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?
 11
Author: Bo Persson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-08 06:25:01

Las"listas inicializadoras" son simplemente kludges horribles.

No:

#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}); }

Do:

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}); }
 16
Author: alecov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-26 05:16:40

Utilice la siguiente sintaxis:

DEMOSTRACIÓN 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
}

Refiérase después de SO.


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

 4
Author: Evgeny Panasyuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:04

De mi discusión con @Evgeny, me di cuenta de que esto solo funciona (con gcc 4.8 c++11) y también puede hacer la comprobación de tamaño aceptando solo un tamaño compatible en la lista de inicialización (en main).

(enlace de 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;
}
 1
Author: alfC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-12 11:12:45