Инициализация статических данных в классе

В С++ члены static не могут быть инициализированы в классе с этими исключениями:

  • static члены const интегрального типа могут быть
  • static члены constexpr литерала типа должны быть

Можете ли вы объяснить, почему эти исключения?

Кроме того, это имеет место:

Даже если элемент данных const static инициализируется в теле класса, этот член обычно должен быть определен вне определения класса.

Это я никогда не понимал. В чем смысл этого дополнительного определения?

Просто пытаясь получить некоторые интуиции здесь.

Ответ 1

Почему в определении класса может быть инициализатор?

Относительно двух исключений для const и constexpr статических данных:

[class.static.data]/3

[Примечание. В обоих случаях член может отображаться в постоянных выражениях. - конечная нота]

т.е. с инициализатором вы можете использовать их в постоянных выражениях, например.

struct s
{
    static std::size_t const len = 10;
    int arr[len];
};
std::size_t const s::len;

Если len не был инициализирован в определении класса, компилятор не мог легко узнать его значение в следующей строке, чтобы определить длину arr.

Можно спорить о разрешении инициализаторов для нестатистических элементов не const, non constexpr в определении класса, но это может помешать порядку инициализации:

[basic.start.init]/2

Определения явно специализированных классов статических элементов шаблона шаблона заказали инициализацию. Другие статические элементы шаблона шаблона класса (т.е. Неявно или явно созданные экземпляры) имеют неупорядоченную инициализацию. Другие нелокальные переменные со статической продолжительностью хранения заказали инициализацию.

То есть порядок определений, включая инициализаторы, важен. Порядок (динамической) инициализации нелокальных объектов определяется только внутри единицы перевода, это еще одна причина, по которой должно быть определение, включающее в себя инициализатор для статических элементов данных < <20 > , не constexpr.


В чем смысл этого дополнительного определения?

Об этом уже ответили в комментариях ИМО. Возможно, вы захотите добавить ODR, то есть как имя с внешней связью, статический член данных должен (только) быть определен в одной единицы перевода (если он используется ODR). Для программиста выберите эту единицу перевода.