TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #362 3.4K
Ответ

Несмотря на всю простоту и краткость кода, он не запустится! Будет ошибка линковки undefined reference to foo::qwerty.

Как такое возможно, если мы четко определили статическое поле qwerty?

Обратимся к стандарту:

If a non-volatile non-inline const static data member is of integral 
or enumeration type, its declaration in the class definition can specify
a brace-or-equal-initializer in which every initializer-clause that is an 
assignment-expression is a constant expression.

The member shall still be defined in a namespace scope if it is odr-used
in the program and the namespace scope definition shall not contain an initializer


Мы хоть и можем указывать инициализатор для константного статического интегрального поля, но это скорее что-то типа маркера инициализации. То есть именно с этим инициализатором будет определяться поле.

И этот маркет не является определением! Оно все равно нужно, так как foo::qwerty odr-использована. Один из признаков того, что переменная odr-используется - на нее ссылается ссылка.

Так вот функция std::max принимает константные ссылки на объекты. А передаем мы в нее lvalue. Значит у этого lvalue должен быть существующий адрес, чтобы нормально забиндится на ссылку.

Вот и получается порочная цепочка: чтобы забиндится на ссылку нам нужен адрес -> адрес глобальная переменная получает только если у нее есть определение -> так как мы используем ссылку на статическое поле класса нам нужно его определение -> мы его не предоставили -> получили по рукам от линкера.

Чтобы избежать ошибки можно использовать 3 стратегии:

👉🏿 Честно предоставить определение, согласно стандарту, без инициализатора.

struct foo {
static const int qwerty = 100;
};
const int foo::qwerty;


👉🏿 Использовать ключевое слово inline, которое, начиная с С++17, позволяет определять поля внутри описания класса.

struct foo {
inline static const int qwerty = 100;
};


👉🏿 Вместо const использовать ключевое слово constexpr. Это фактически сразу делает qwerty компайл тайм константой, которая должна быть инициализирована при объявлении и к которой спокойно можно обращаться в том числе и по ссылке.

struct foo {
static constexpr int qwerty = 100;
};


Вот такое тонкое место есть в С++)

Surprise everyone. Stay cool.
  • 👍 32
  • ❤‍🔥 11
  • ⚡ 6
  • 🔥 6
  • ❤ 1
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →