Предположим, что у меня есть статический класс шаблона в файле "Foo.h", например:
template<typename T> class Foo
{
public:
static T foo1();
static T foo2();
static T foo3();
static T foo4();
static T foo5();
};
// definitions...
Теперь предположим, что у меня есть файл "main.cpp":
#include "Foo.h"
main()
{
double value = Foo<double>::foo3();
// Do something with value
return 0;
}
Когда я скомпилирую этот файл, будут ли методы foo1()
, foo2()
, foo4()
и foo5()
также присутствовать в сгенерированном коде?
Нет, будет foo3
только foo3
. Функции-члены шаблона класса рассматриваются как отдельные шаблоны, и каждый из них создается только в том случае, если он используется (или явно создается экземпляр).
Вы сами это видите, поставив код в одну из неиспользуемых функций, которые не будут компилироваться при создании экземпляра с double
, например
static T foo1() {return T().nonsense;} // double has no members
Ваш код, который использует только foo3
, все равно будет компилироваться, так как он не будет пытаться создать его.
Нет.
C++ Стандарт 14.7.1/10
Реализация не должна имплицитно создавать шаблон функции, шаблон-член, не виртуальную функцию-член, класс-член или статический элемент данных шаблона класса, который не требует создания экземпляра. (...)
Это чрезвычайно полезный метод, особенно в сочетании с политикой. Вы можете в основном определить функции-члены, которые работают только для некоторых параметров шаблона; если вы не используете их в таких случаях, вы не получите ошибку компиляции.
Нет.
C++ 14.7.1/1-2, акцент мой:
Неявное создание экземпляра специализации шаблона вызывает неявное создание деклараций, но не определений или аргументов по умолчанию, функций- членов класса, классов-членов, облачных имен элементов, статических элементов данных и шаблонов-членов; и это приводит к неявному созданию определений индексированных имен элементов и анонимных союзов участников.
Если член шаблона класса или шаблон-член явно не создавался или не был явно специализирован, специализация этого элемента неявно создается, когда специализация ссылается в контексте, который требует определения члена.
Таким образом, ваш пример будет даже правильным, если, например, включение double
для определения double Foo<double>::foo1()
приведет к ошибке.
С другой стороны, если вы использовали явное создание экземпляра класса:
template class Foo<double>;
то все элементы создаются.
Это легко проверить. Когда я помещаю ваш код в файл и компилирую его с помощью gcc
g++ -g a.cpp
Я получаю двоичный файл a.out. Теперь я могу изучить его с помощью nm
nm a.out | grep foo
который дает
00000000004004dc W _ZN3FooIdE4foo3Ev
Итак, нет foo1
или любого другого рядом с foo3