static_assert в initializer_list :: size () - PullRequest
       31

static_assert в initializer_list :: size ()

29 голосов
/ 26 марта 2011

Почему std :: initializer_list <_E> :: size недопустим в static_assert, даже если он объявлен как constexpr в моем libstdc ++ (v. 4.6)?

Например, следующий код:

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

выдает следующую ошибку:

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

Обратите внимание, что это прекрасно работает для тривиального примера:

class A
{
  public:
    constexpr int size() { return 5; }
};

int main()
{
  A a;
  static_assert(a.size() == 4, "oh no!");

  return 0;
}

Ответы [ 4 ]

19 голосов
/ 31 июля 2016

«Списки инициализаторов» - это просто ужасные ошибки.

Не

#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}); }
11 голосов
/ 26 марта 2011

Компилятор говорит, что проблема заключается в init, а не в init.size ().

Я предполагаю, что конструктор можно вызывать из разных мест с инициализаторами разной длины.

(Разработать: Вы пытаетесь записать static_assert, которое зависит от времени выполнения значения переменной init, а именно от того, сколько элементов у нее есть. static_assert s должны быть оценены в данный моментфункция скомпилирована. Ваш код аналогичен этому тривиально неверному примеру:)

void foo(int i) { static_assert(i == 42, ""); }
int main() { foo(42); }  // but what if there's a caller in another translation unit?
4 голосов
/ 09 апреля 2013

Используйте следующий синтаксис:

LIVE DEMO

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

См. после SO .


РЕДАКТИРОВАТЬ: Интересно, что работает на GCC 4.8.1, но не работает на Clang 3.4.Может быть, это связано с constexpr из .size() (afaik, в C ++ 14 это constexpr).

1 голос
/ 12 ноября 2013

Из моего обсуждения с @Evgeny я понял, что это просто работает (с gcc 4.8 c++11) и может также выполнять проверку размера, принимая только совместимый размер в списке инициализатора (в main).

(кодовая ссылка: 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...