TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #223 4.72K
Когда НЕ стоит использовать extern template

Если вы будете гуглить инфу по этой теме, то непременно нарветесь на неправильное понимание принципов работы фичи. Стопроцентов вы наткнетесь на такое объяснение:

extern template в связке с явным инстанцированием шаблона помогает предотвратить дублирование кода в TU и уменьшить время компиляции. Выглядит это так:

// ship.hpp
#pragma once
template<typename T>
struct Ship
{
void TurnShip(T command);
};

// ship.cpp
#include "ship.hpp"

template <class T>
void Ship<T>::TurnShip(T command) {}

template struct Ship<int>; // explicit instantiation definition

// main.cpp
#include "ship.hpp"

extern template struct Ship<int>; // explicit instantiation declaration

int main() {
Ship<int> ship;
ship.TurnShip(5);
}

Типа вот мы в ship.cpp добавили явную конкретизацию шаблона, а в мэйне объявили, что возьмем информацию о специализации в другом месте.

Но дело в том, что в этом случае extern template - лишний! В нем нет никакого смысла и вот почему.

Если мы уберем extern template из файла main, то ничего не изменится. Так как в этой единице трансляции и так никогда бы не была конкретизирована специализация Ship<int>. Потому что компилятору на момент компиляции файла main.cpp видно только объявление шаблона из файла ship.hpp и у него недостаточно информации для инстанцирования. И только при линковке линковщик найдет все символы в единице трансляции, соответствующей ship.cpp, и сгенерирует рабочую программу.

Так что запомните: если вы используете явную инстанциацию после определения шаблона в цппшнике и подключаете хэдэр с его объявлением, то вам НЕ НУЖНО использовать extern template.

Это кстати отличная защита от тех самых проблем при работе с шаблонами. Так что выносить определенения шаблонов в цппшники и делать в них явную инстанциацию - полезная вещь.

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

А вот когда это нужно использовать. Только тогда, когда у вас есть несколько единиц трансляции, где компилятор сам неявно может инстанцировать одинаковые специализации. Например, когда вы полностью определяете шаблон в хэдэре и везде его распространяете таким образом. Тогда получается, что без использования extern template в каждой из этих единиц трансляций, подключивших хэдэр с шаблоном и использующих одинаковую специализацию, эта специализация будет инстанцирована. Это значит, что код для нее будет присутствовать во всех объектниках. Это приводит к его дублированию и увеличению времени компиляции.

Теперь мы во всех TU, кроме одной, используем extern template и в этой оставшейся делаем явную специализацию. Получается, что для всех, кроме одной, TU компилятору будет запрещено самостоятельно инстанцировать эту специализацию. И все они будет обращаться в тот единственный объектник, в котором есть код для специализации. Именно за счет этого и не происходит раздувания итогового бинарника. Все просто полагаются на одну копию.

Rely on original information. Stay cool.

#cpp11 #cppcore #template #compiler
  • 👍 18
  • ❤ 4
  • 🔥 2
  • 👎 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 →