extern template с шаблонами STL
Обещал рассказать, почему вы не сможете подавить неявную инстанциацию для STL сущностей. Это будет хорошим завершением серии, потому что включает множество обсужденных концепций и особенностей.
Оговорюсь, что буду говорить за реализацию стандартной библиотеки от gcc.
Начнем с того, что фичи стандартных шаблонов распространяются и подключаются с помощью хэдэр-файлов. И если внимательно посмотреть на эти хэдэра, то мы можем увидеть, что авторы библиотеки помещают методы шаблонных классов внутрь определения классов(за все-превсе классы не могу сказать, но тенденция явно проглядывается).
Далее. Единственным способом запретить неявное инстанцирование при распространении кода с помощью заголовочников - с помощью extern template. Все конкретизации мы не можем запретить, но самые популярные - можем попробовать. В случае успеха это будет давать большой импакт к уменьшению времени компиляции и размеру объектников.
А в недавнем посте "Не всегда инстанциация шаблона нужна для работы программы" мы поговорили о том, что методы, определенные внутри описания класса, неявно помечаются inline. А для inline функций запрет на неявное инстанцирование не работает!
Поэтому для шаблонов STL(под этим акронимом я понимаю все шаблонные классы стандартной библиотеки) вы просто не сможете получить никакого профита от extern template. Стандарт это явно запрещает.
Получается, что все разговоры про запрет или ограничение неявного инстанцирования касаются лишь только кастомного кода. Ограничения на стандартные инструменты наложить не получится, как и поиметь соотвествующих плюшек. Sad, but true. Об этой особенности очень мало говорят даже в англоязычном пространстве. Поэтому вы теперь элита и эксперты в правильной организации шаблонного кода.
Use your tools in proper places. Stay cool.
#cpcore #template #compiler
Обещал рассказать, почему вы не сможете подавить неявную инстанциацию для STL сущностей. Это будет хорошим завершением серии, потому что включает множество обсужденных концепций и особенностей.
Оговорюсь, что буду говорить за реализацию стандартной библиотеки от gcc.
Начнем с того, что фичи стандартных шаблонов распространяются и подключаются с помощью хэдэр-файлов. И если внимательно посмотреть на эти хэдэра, то мы можем увидеть, что авторы библиотеки помещают методы шаблонных классов внутрь определения классов(за все-превсе классы не могу сказать, но тенденция явно проглядывается).
Далее. Единственным способом запретить неявное инстанцирование при распространении кода с помощью заголовочников - с помощью extern template. Все конкретизации мы не можем запретить, но самые популярные - можем попробовать. В случае успеха это будет давать большой импакт к уменьшению времени компиляции и размеру объектников.
А в недавнем посте "Не всегда инстанциация шаблона нужна для работы программы" мы поговорили о том, что методы, определенные внутри описания класса, неявно помечаются inline. А для inline функций запрет на неявное инстанцирование не работает!
Поэтому для шаблонов STL(под этим акронимом я понимаю все шаблонные классы стандартной библиотеки) вы просто не сможете получить никакого профита от extern template. Стандарт это явно запрещает.
Получается, что все разговоры про запрет или ограничение неявного инстанцирования касаются лишь только кастомного кода. Ограничения на стандартные инструменты наложить не получится, как и поиметь соотвествующих плюшек. Sad, but true. Об этой особенности очень мало говорят даже в англоязычном пространстве. Поэтому вы теперь элита и эксперты в правильной организации шаблонного кода.
Use your tools in proper places. Stay cool.
#cpcore #template #compiler
Константная инициализация. Ч2
То, каким образом в деталях работает константная иницализация, довольно сложно понять, просто читая стандарт и другие официальные источники. И вот почему.
Вот такой пример они дают:
И говорится, что
Но видимо при проведении константной инициализации компилятор только один раз проходит сверху вниз программы. По факту,
Еще более интересные вещи происходят в ассемблер
Это внутреннее представление этих глобальных переменных. static_class_var прям глобальная, ее могу видеть и другие единицы трансляции. Поэтому она с пометкой .globl. const_var же статическая переменная, а значит ее видно видно только из текущей единицы трансляции.
Проблема в том, что
Дело в том, что здесь замешано одно интересное право компилятора. Ему в определенных случаях разрешено устанавливать начальные значения переменным в compile-time, если он уверен, что их значения не изменится на момент начала старта программы.
Этот пример и пример из прошлого поста кстати показывают, что инициализация глобальных переменных идет не совсем сверху вниз. Для каждого этап инициализации это более менее верно, но под каждый этап попадают разные подмножества переменных. Поэтому могут возникать сайд-эффекты, подобные тем, что были в этом посте.
Accept side affects. Stay cool.
#cpcore #compiler
То, каким образом в деталях работает константная иницализация, довольно сложно понять, просто читая стандарт и другие официальные источники. И вот почему.
Вот такой пример они дают:
struct S
{
static const int static_class_var;
};
static const int const_var = 10 * S::static_class_var;
const int S::static_class_var = 5;
int main()
{
std::cout << &const_var << std::endl; // ODR-use for explicit generation of symbol
std::array<int, S::static_class_var> a1; // OK
// std::array<int, const_var> a2; // ERROR
}
И говорится, что
static_class_var
на момент создания const_var
не имеет инициализатора. А так как компилятор в первую очередь выполняет константную инициализацию, поэтому он не может сейчас установить значение для const_var
. Поэтому в начале инициализируется static_class_var
. И вот уже дальше - const_var
.Но видимо при проведении константной инициализации компилятор только один раз проходит сверху вниз программы. По факту,
static_class_var
- константа, инициализированная константным выражением. И по всем канонам должна сама стать константным выражением. Так и получается, ведь мы можем создать std::array из нее. Но вот из const_var
- не можем. Хотя эта переменная тоже проинициализирована константным выражением. Но так, как ее инициализация происходит после константной инициализации, то этот факт не дает ей шанса стать нормальным constant expression.Еще более интересные вещи происходят в ассемблер
е.
.section __TEXT,__const
.globl __ZN1S16static_class_varE ## @_ZN1S16static_class_varE
.p2align 2, 0x0
__ZN1S16static_class_varE:
.long 5 ## 0x5
.p2align 2, 0x0 ## @_ZL9const_var
__ZL9const_var:
.long 50 ## 0x32
Это внутреннее представление этих глобальных переменных. static_class_var прям глобальная, ее могу видеть и другие единицы трансляции. Поэтому она с пометкой .globl. const_var же статическая переменная, а значит ее видно видно только из текущей единицы трансляции.
Проблема в том, что
const_var
выглядит такой же compile-time константой, как и static_class_var
. Хотя по идее тут должна быть какая-нибудь zero-инициализация + динамическая в рантайме. Но array мы не можем создать с const_var
🗿.Дело в том, что здесь замешано одно интересное право компилятора. Ему в определенных случаях разрешено устанавливать начальные значения переменным в compile-time, если он уверен, что их значения не изменится на момент начала старта программы.
Этот пример и пример из прошлого поста кстати показывают, что инициализация глобальных переменных идет не совсем сверху вниз. Для каждого этап инициализации это более менее верно, но под каждый этап попадают разные подмножества переменных. Поэтому могут возникать сайд-эффекты, подобные тем, что были в этом посте.
Accept side affects. Stay cool.
#cpcore #compiler