Рассмотрим следующие две единицы перевода:
// foo.cpp
#include <iostream>
class Foo {
public:
virtual ~Foo() = default;
virtual void bar();
private:
static int _baz;
};
static int f() {
std::cout << "f called\n";
return 42;
}
int Foo::_baz = f();
void Foo::bar() {
std::cout << "Baz::bar called\n";
}
и
// main.cpp
#include <iostream>
int main() {
std::cout << "main called\n";
}
При компиляции обоих модулей перевода в один исполняемый файл (например, с помощью g++ -std=c++17 main.cpp foo.cpp
, выбор уровня оптимизации или упорядочение двух файлов cpp не имеет значения), результирующий исполняемый файл печатает
f называется
основной называется
независимо от того, какой из трех основных компиляторов GCC, clang и MSVC использовался для его компиляции. Вы можете увидеть поведение для себя на wandbox .
Мой вопрос: гарантирует ли стандарт, что Foo::_baz
будет инициализирован (и, следовательно, будет вызываться f
) , даже если весь класс Foo
не используется в программе вообще
Я считаю, что это так; мои рассуждения звучат так:
Согласно [basic.start.dynamic] / 4 , Foo::_baz
не нужно инициализировать перед выполнением первого оператора main, но
если [инициализация] откладывается, то это происходит до того, как любое использование неинициализации odr любой не встроенной функции или не встроенной переменной, определенной в той же единице перевода, что и инициализируемая переменная.
Здесь "неиспользование odr-использования" определяется как
[...] использование odr ([basic.def.odr]), не вызванное прямо или косвенно инициализацией нелокальной статической переменной или переменной продолжительности хранения потока
in [basic.start.dynamic] / 3 . Но согласно [basic.def.odr] / 7 ,
функция виртуального члена используется odr, если она не является чистой.
, из которого я заключаю, что определение Foo::bar
- это использование не инициализации odr-использования не встроенной функции, определенной в той же единице перевода, что и Foo::_baz
, и, таким образом, Foo::_baz
будет инициализировано.
Что я нахожу странным в этой строке рассуждений, так это то, что отложенная инициализация Foo::_baz
должна произойти до использования odr Foo::bar
, то есть до того, как будет определено Foo::bar
(wtf ?!) с момента определения один - использование одр. Это заставляет меня думать, что мои рассуждения могут быть ошибочными.
Итак, еще раз: гарантирует ли стандарт, что Foo::_baz
будет инициализирован (и, следовательно, будет вызываться f
) , даже если ничего в его единице перевода никогда не используется в программе вообще ? Если да, есть ли что-то, что мы можем сказать о , когда это произойдет (учитывая странное ограничение порядка, которое должно произойти до того, как будет определена функция виртуального члена), и если нет, где ошибка в моих рассуждениях?