C++ разница между определением и инициализацией?
Липпман, Лажойе... Программирование C++. Базовый курс. 5-е издание. 390 страница. Из прочитанного понял следующее: Статические переменные класса, обязательно надо определять вне класса. Но если очень хочется инициализировать внутриклассовым инициализатором, то эта переменная должна быть целочисленной и константной.
Обратите внимание на: "не следует определять отдельно" и "определение для этого члена необходимо". Но только static constexpr (или к примеру const) int не возможно определить как
constexpr int Account::period = 30;
То есть почему в одном абзаце написано то, что не работает дляя static const int? Или Я не правильно понял и имелось ввиду что обсуждается "в общем" любой static int? Хотя в самом незу часть кода показывает что всё таки можно:
constexpr int Account::period;
То есть получается что такой код тоже называется определением, но у него нет же инициализатора. Я у себя в голове отложил что определение может быть только одно и оно должно соправаждаться инициализацией, или же инициализация в классе и определение в не класса это разные вещи? Я вот всегда думал что инициализация сразу при объявлении равносильно определению. Или Я что то не правильно понял? Подскажите пожалуйста. Спасибо.
Ответы (1 шт):
Во-первых, это устаревшая информация времен C++14. В С++17 и новее static constexpr
переменным никогда не нужно дополнительное определение, все работает без него (независимо от того как переменная используется) (для любого типа, не только целочисленных).
Отдельное определение все еще нужно если написать static const int x = 42;
(то есть не constexpr
, не inline
, есть инициализатор, и целочисленного типа (для других типов не компилируется)).
Обратите внимание на: "не следует определять отдельно" и "определение для этого члена необходимо".
Здесь "не следует" - это рекомендация (рекомендация не писать лишнего). Не будет ничего страшного если написать. И дальше автор наоборот рекомендует всегда писать.
Остальную часть вопроса не понимаю, подозреваю что тут путаница в терминах.
"Иницаилизация" в С++ - это создание объекта во время работы программы (обычно с установкой начального значения, но строго говоря это даже без него "инициализация"). В общепрограммистском смысле это означает "установка начального значения".
"Определение" - это запись в коде программы, которая говорит компилятору создать объект, определенного вида (обычно
тип имя;
илитип имя = значение;
). Все (?) определения также считаются объявлениями."Объявление" - это либо определение, либо запись в коде программы, сообщающая компилятору, что объект скорее всего будет определен где-то еще, и позволяет его использовать не видя определения. Тоже обычно имеет вид
тип имя;
.
А теперь с примерами:
struct A
{
static int v1;
- Объявление.static const int v2;
- Объявление.static constexpr int v3;
- Не компилируется.static int v4 = 42;
- Не компилируется.static const int v5 = 42;
- Объявление, а точнее "инициализируещее объявление" (хотя в C++14 такого термина еще не было).static constexpr int v6 = 42;
- Объявление в C++14, определение в C++17. В С++17 автоматическиinline
.
Ну и inline
-переменные из C++17.
inline static int v7 = 42;
- Определение.inline static const int v8 = 42;
- Определение.inline static constexpr int v9 = 42;
- Определение.
};
int A::v1;
- Определение.const int A::v2 = 42;
- Определение, без инициализатора не компилируется.const int A::v5;
- Определение.const int A::v6;
- Определение. В С++17 это уже второе объявление той же переменной, но не ошибка, потому чтоinline
.
То есть наличие инициализатора - не означает что это определение. Это может быть "инициализирующее объявление". И наоборот, отсутствие инициализатора - не значит что это не определение.
Ссылки:
- https://timsong-cpp.github.io/cppwp/n4140/class.static#data-2 - в C++14 объявление
static
переменной внутри класса никогда не является определением. - https://eel.is/c++draft/class.mem#class.static.data-3 - в более новом C++ оно является определением если переменная inline, т.е. либо явно
inline
, либо автоматчиески потомуconstexpr
: https://eel.is/c++draft/dcl.constexpr#1
Для общего развития, использование переменной не в "контекстах, где компилятор может подставить [ее] значение" называется odr-use и требует существования определения.