Это довольно интересный вопрос, который следует задать в более широком контексте того, как шаблоны обрабатываются компилятором.В основном шаблоны - это шаблоны кода, из которых компилятор генерирует классы функций.Шаблон может быть использован для генерации чего-либо: от отсутствия кода вообще (если он никогда не использовался) до неопределенного числа экземпляров.
Шаблоны не напрямую скомпилированы в любой объект, который позже.используется с другими аргументами (что верно в обобщениях C #, но не в C ++), но скорее код анализируется компилятором и сохраняется в памяти на случай, если он будет позже использован при обработке текущего модуля перевода.То есть компилятор обрабатывает шаблон ( шаблон курсивом используется в английской форме шаблона, из которого создаются вещи, а не точное значение C ++), из которого он будет созданкод (классы или функции) при необходимости. Instantiation - это процесс, с помощью которого компилятор определяет, что конкретный шаблон используется с определенным набором аргументов, и выполняет подстановку аргументов в шаблоне для генерации класса или функции для компиляции и окончательной компиляции в двоичный код шаблона.
Существует два типа реализации шаблона: неявный и явный и цитата, на которую вы ссылаетесь, о неявных шаблонах .Я начну с явной реализации шаблона только потому, что он проще.Когда вы явно создаете экземпляр шаблона (Google для синтаксиса), вы сообщаете компилятору, что вы хотите, чтобы код, сгенерированный из этого шаблона , применялся к конкретным аргументам, которые вы предоставляете.В случае class-template это вызывает создание экземпляров всех функций-членов, что в основном означает, что компилятор подставит типы и скомпилирует результат этого в двоичные объекты.
Неявная реализация , с другой стороны, выполняется по требованию.Когда вы используете шаблон класса, биты и кусочки, которые на самом деле используются , генерируются из шаблона и компилируются в модуль перевода.Если вы создаете определение переменной std::vector<int> v;
, компилятор применяет тип int
(и тип по умолчанию std::allocator<int>
) к template std::vector
и создает тип std::vector<int>
, но при этом он не компилируетсявсе функции-члены, но только те, которые необходимы, что в данном случае будет конструктором по умолчанию std::vector<int>::vector()
и деструктором std::vector<int>::~vector()
.Остальные методы не компилируются, и для них не будет кода в двоичном виде.
Есть несколько причин, по которым не создаются не все функции-члены, и причиныварьируются по сложности от простых до глубоких языковых деталей.Для некоторых из более простых вы можете рассмотреть производительность компиляции (отсутствие необходимости генерировать / компилировать все функции-члены только потому, что используется одна из них, значительно сократит время компиляции).Немного более сложным является тот факт, что различные функции-члены в шаблоне могут предъявлять разные требования к типу экземпляра.Например, operator[]
для map
требует, чтобы тип значения был default-constructible , так как оператор создаст новый элемент, если он еще не существовал на карте, с другойстороны, если вы всегда используете find
и insert
, вы можете использовать std::map
с типами, которые не могут быть использованы по умолчанию.Не заставляя компилировать все функции-члены, язык позволяет использовать шаблон с аргументами, которые не будут отвечать всем требованиям всех методов, если он действительно соответствует требованиям тех методов, которые на самом деле используется .
Я использовал термин , довольно часто используемый в описаниях выше, но я еще не определил его.Для точного определения вам нужно перейти к стандарту, но вы можете считать хорошим приближением, что функция-член используется , если она вызывается прямо или косвенно из вашего кодат.е. вы вызываете его, или какая-либо другая функция-член, которую вы вызываете, вызывает его), или если вы получаете адрес функции-члена.