У меня есть класс шаблона C++, который создается с тремя разными параметрами типа. Есть метод, который класс должен иметь только для одного из этих типов, и который никогда не вызывается с двумя другими типами.
Будет ли объектный код для этого метода сгенерирован трижды (для всех типов, для которых создается шаблон) или объектный код создается только один раз (для типа, с которым он фактически используется)?





Обычно да.
Все, что компилятор действительно знает, это то, что ваша программа может создать хотя бы один экземпляр каждого класса. Но он не знает, что вы будете делать с этими экземплярами. Так что код почти наверняка будет сгенерирован.
Тем не менее, если рассматриваемые методы являются виртуальными нет и никогда не вызываются, компоновщик может удалить их с помощью своих обычных функций удаления мертвого кода. Таким образом, сгенерированный (и скомпилированный) код не будет в окончательном EXE.
Также это будет во многом зависеть от используемого компилятора C++, потому что они не все одинаковы.
Виртуальные функции-члены создаются при создании экземпляра шаблона класса, но невиртуальные функции-члены создаются только в том случае, если они вызываются.
Это описано в [temp.inst] стандарта C++ (в C++ 11 это §14.7.1 / 10. В C++ 14 это §14.7.1 / 11, а в C++ 17 это §17.7.1 / 9. Выдержка из C++ 17 ниже)
An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, a static data member of a class template, or a substatement of a
constexprif statement (9.4.1), unless such instantiation is required
Также обратите внимание, что можно создать экземпляр шаблона класса, даже если некоторые из функций-членов не могут быть созданы для заданных параметров шаблона. Например:
template <class T>
class Xyzzy
{
public:
void CallFoo() { t.foo(); } // Invoke T::foo()
void CallBar() { t.bar(); } // Invoke T::bar()
private:
T t;
};
class FooBar
{
public:
void foo() { ... }
void bar() { ... }
};
class BarOnly
{
public:
void bar() { ... }
};
int main(int argc, const char** argv)
{
Xyzzy<FooBar> foobar; // Xyzzy<FooBar> is instantiated
Xyzzy<BarOnly> baronly; // Xyzzy<BarOnly> is instantiated
foobar.CallFoo(); // Calls FooBar::foo()
foobar.CallBar(); // Calls FooBar::bar()
baronly.CallBar(); // Calls BarOnly::bar()
return 0;
}
Это действительно, хотя Xyzzy :: CallFoo () не может быть создан, потому что не существует такой вещи, как BarOnly :: foo (). Эта функция часто используется как инструмент метапрограммирования шаблонов.
Обратите внимание, однако, что «создание экземпляра» шаблона напрямую не коррелирует с тем, сколько генерируется объектного кода. Это будет зависеть от реализации вашего компилятора / компоновщика.
Сделанный. Я думал об этом, когда сначала отвечал, но мне было лень написать полное объяснение.
Можно ли пометить метод для принудительного создания экземпляра (т.е. предотвратить его оптимизацию), не делая его виртуальным? Спасибо!
Думаю, это зависит от компилятора и настроек. Например, я считаю, что MSVC6 сгенерировал все, а VS2005 - нет. В спецификации говорится, что компилятор не должен этого делать, но в реальном мире это зависит от фактического компилятора (например, для MSVC6 есть много обходных путей). Компоновщик может удалить функции, на которые нет ссылок, если включен / opt: ref (для VS аналогичные параметры существуют для других компиляторов).
Старый добрый MSVC6 и шаблоны, ах дни ... ужас.
Мы также должны отметить, что не все функции могут быть даже созданы, и это нормально, пока они не вызываются.