Где должно быть размещено определение явной специализации шаблона класса В C++?
по данным [temp.spec] / 5:
для данного шаблона и заданного набора аргументов шаблона,
...
явная специализация определяется не более одного раза в программе (согласно [basic.защита.odr]), и
...
определение явной (полной) специализации класса шаблон не может быть помещен в заголовок (в противном случае в каждой единице перевода, содержащей этот заголовок, есть одно определение, поэтому во всей программе будет более одного определения).
кроме того, в качестве еще одного доказательства, объекты, перечисленные в [basic.защита.odr] / 12 (blockquoted ниже) не содержат полной специализации шаблона класса. Вместо этого "специализация шаблона для которого некоторые параметры шаблона не указаны " is заключенный.
может быть более одного определения типа класса, типа перечисления, встроенной функции с внешней связью ([dcl.inline]), встроенная переменная с внешним рычагом ([dcl.inline]), шаблон класса, шаблон нестатической функции, концепция ([temp.концепция]), статический элемент данных шаблона класса, функция-член шаблона класса или специализация шаблона, для которой некоторые параметры шаблона не являются указано ([temp.spec], [temp.класс.spec]) в программе при условии, что каждое определение отображается в другой единице перевода, и при условии, что определения удовлетворяют следующим требованиям.
однако, если я помещаю определение в исходный файл и оставляю его объявление в заголовке, например,
// "a.h"
template <typename T>
struct S {};
template <>
struct S<int>; // declaration
// "a.cpp"
#include "a.h"
template <>
struct S<int> {}; // definition
// "main.cpp"
#include "a.h"
int main()
{
S<int> s;
}
затем возникает ошибка ( протестировано gcc), поскольку S<int>
неполный тип.
In заключение, где я должен разместить определение явной специализации шаблона класса?
3 ответов
Я постараюсь изложить здесь то, что я узнал через обсуждение в моем другом ответе, в надежде оставить хороший ответ на этот вопрос, а не похоронить ответ в комментариях.
стандарт говорит
явная специализация определяется не более одного раза в программе (в соответствии с ODR)
ODR является одним правилом определения. Вы можете определить каждый класс только один раз в a программа, за исключением случаев, когда определение класса доступно в каждой единице перевода: вы можете определить класс в разных единицах перевода, если эти разные определения идентичны, символ для символа. Цитата OP является частью описания ODR, следуйте ссылка OP чтобы увидеть полное описание.
таким образом, ИМО текст стандарта выше означает, что явная специализация может быть определена только один раз, но в соответствии с ODR, и, таким образом, с теми же исключениями: вы можете определить его в заголовочном файле, чтобы он был доступен в нескольких единицах перевода.
обратите внимание, что невозможно создать экземпляр класса без его полного определения (компилятор должен знать, по крайней мере, сколько байтов выделить для него). То же самое верно для шаблонного класса или специализации такого класса. Так это должны можно, чтобы определение присутствовало в каждой единице перевода, которая его использует.
это определение (специализация будет инстанцирована), а не объявление, оно, вероятно, должно идти в определенном исходном файле (*.cpp):
template <> struct S<int>;
Примечание: это не "больно" иметь это в каждой единице перевода... кроме времени, необходимого для создания экземпляра компилятором, и раздувания объектных файлов (*.o или *.параметр obj.)
это объявление (специализация не будет создана), и можно поместить в файл заголовка (*.h):
extern template <> struct S<int>;
объявление требует C++11 или более поздней версии.
вы не можете instantuate класс, который не полностью определен в ЕП. Специализации шаблонов классов принадлежат заголовочному файлу. Вы можете написать специализацию функции или метода в отдельной единице перевода:
// "a.h"
template <typename T>
struct S {
void fun();
};
// "a.cpp"
#include "a.h"
template<>
void S<int>::fun() {
std:cout << "int!\n"
}; // definition
// "main.cpp"
#include "a.h"
int main()
{
S<int> s;
s.fun();
}
изменить:
когда стандарт говорит
явная специализация определяется не более одного раза в программе (согласно [basic.защита.odr])
Он говорит, что вы не можете иметь более одного определения согласно ODR. То же самое верно для всего остального: вы не можете объявить два разных класса с одинаковым именем, поэтому вы не можете объявить две разные специализации с одинаковыми параметрами шаблона. Размещение определения класса в файле заголовка не нарушает ODR. Как и специализация шаблона класса.