Почему inline требуется для статических встроенных переменных?

С++ 17 позволяет определять статические переменные-члены следующим образом:

class X {
  public:
    static inline int i = 8;
};

В чем причина требования спецификации inline? Почему бы просто не позволить программистам писать

    static int i = 8;

в классе?


person oz1cz    schedule 22.10.2017    source источник
comment
Проверьте этот вопрос и ответ, он может дать вам некоторое представление о том, почему.   -  person Sergey.quixoticaxis.Ivanov    schedule 22.10.2017


Ответы (1)


Без inline это явно указано только как объявление. Как указано в [class.static.data]/2

Объявление невстроенного статического члена данных в его определении класса не является определением и может иметь неполный тип, отличный от cv void. Определение статического члена данных, который не определен как встроенный в определение класса, должно появиться в области пространства имен, охватывающей определение класса члена.

Обоснование, скорее всего, состоит в том, чтобы сохранить устаревший код неповрежденным и действительным. Вспомните, что мы могли инициализировать целочисленные константы в самом определении класса почти всегда. Но odr-использование их по-прежнему требовало внеклассового определения в какой-то единице перевода.

Таким образом, сделать такие переменные неявно встроенными может быть проблематично в существующих кодовых базах. Комитет всегда думает об обратной совместимости при добавлении основных функций языка.

Например, рассмотрим это допустимое определение класса C++03:

struct foo {
    static const int n = 3;
    double bar[n];
};

n можно использовать как константное выражение для определения степени bar, и это не считается использованием odr. В настоящее время мы бы написали это как constexpr1, однако указанное выше по-прежнему актуально. Но могут быть случаи, когда n придется использовать odr (представьте, что его адрес взят, или ссылка привязана к нему и т. д.). Их, вероятно, не так много и, вероятно, они не распространены, но у некоторых API есть сумасшедшие требования, которые в конечном итоге потребуют этого.

const int foo::n;

появляться в какой-либо единице перевода.

Теперь, если бы static inline int i = 8; вдруг неявно стало inline, приведенное выше определение (то есть в существующей кодовой базе) было бы нарушением ODR. Теперь ранее хорошо сформированный код плохо сформирован. Поэтому лучше всего разрешить здесь действовать только явным inline, так как на самом деле они будут только в новом коде.


1 Можно возразить, что static constexpr переменные могут иметь одинаковую проблему (и тем не менее они неявно встроены). Но их первоначальная формулировка IIRC позволила это изменение без потенциального нарушения существующего кода. По сути, он уже был «встроенным» во всем, кроме имени.

person StoryTeller - Unslander Monica    schedule 22.10.2017
comment
Этот ответ был бы лучше с реальным примером проблемного поведения - person Yakk - Adam Nevraumont; 22.10.2017
comment
Предложение кода OP уже плохо сформировано, поэтому изменение не нарушит существующий код. Но это было бы несколько нелогично - person M.M; 22.10.2017
comment
@M.M - код ОП. Но такое же обращение должно применяться к элементам данных const, которые имеют правильный формат. В любом случае, я в процессе расширения. Момент - person StoryTeller - Unslander Monica; 22.10.2017
comment
@Yakk - Лучше? Я чувствую, что, возможно, ошибся в записке о constexpr. - person StoryTeller - Unslander Monica; 22.10.2017
comment
Только немного лучше; тот факт, что const int foo::n; вызывает нарушение ODR из-за отсутствия inline, не является существенной частью ключевого слова inline, а скорее выбором реализации ключевого слова inline здесь. Таким образом, отказ от предположения inline теперь заключается в том, что они решили, что будет нарушением ODR использовать inline в объявлении, а затем определить его без inline, что просто отбрасывает вопрос, почему они выбрали это нарушение ODR. Подозреваю по аналогии с inline функциями? Но есть ли другая причина? - person Yakk - Adam Nevraumont; 23.10.2017
comment
static constexpr был сделан неявно встроенным, превратив то, что было определением, в избыточное повторное объявление - см. [depr.static_constexpr]. Итак... что мешает комитету сделать то же самое здесь? - person T.C.; 24.10.2017
comment
@ T.C. - А семантика static constexpr, применимая ко всем типам, применима к static const, но только к целочисленным типам? Это кажется более неудобным, чем то, как это указано в настоящее время. Я могу представить комитет, желающий играть в консерватор. Кроме того, IMO мы все равно должны использовать для этого constexpr, и старый код (который больше не нуждается в старых цепочках инструментов) должен быть соответственно обновлен. Но опять же, это я, а не комитет. - person StoryTeller - Unslander Monica; 24.10.2017