According to [temp.spec]/5:
For a given template and a given set of template-arguments,
the definition of an explicit (full) specialization of a class template cannot be placed in a header (otherwise there is one definition in each translation unit containing this header, thus there will be more than one definition in the whole program).
In addition, as another evidence, the entities listed in [basic.def.odr]/12 (blockquoted below) do not contain a full specialization of a class template. Instead, "template specialization for which some template parameters are not specified" is contained.
There can be more than one definition of a class type, enumeration type, inline function with external linkage ([dcl.inline]), inline variable with external linkage ([dcl.inline]), class template, non-static function template, concept ([temp.concept]), static data member of a class template, member function of a class template, or template specialization for which some template parameters are not specified ([temp.spec], [temp.class.spec]) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.
However, if I place the definition in a source file and leave its declaration in a header, for example,
// "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;
}
then an error occurs (tested by gcc) because S<int>
is an incomplete type.
In conclusion, where should I place the definition of an explicit specialization of a class template?
I am going to try to summarize here what I've learned through the discussion in my other answer, in the hopes of leaving a good answer to this question, rather than having the answer be buried in the comments.
The standard says
an explicit specialization shall be defined at most once in a program (according to ODR)
ODR is the One Definition Rule. You can only define each class once within a program, with an exception designed to allow a class definition to be available in each translation unit: you can define a class in different translation units as long as these different definitions are identical, character for character. The quote of the OP is part of the ODR description, follow the OP's link to see the full description.
So IMO the standard's text above means that an explicit specialization can be defined only once, but according to the ODR, and thus with the same exceptions: you can define it in a header file so it is available in multiple translation units.
Note that it is not possible to instantiate a class without its full definition (the compiler needs to know at least how many bytes to allocate for it). The same is true for a templated class, or a specialization of such a class. So it must be possible for the definition to be present in each translation unit that uses it.
This is a definition (the specialization will be instantiated), not a declaration, it probably ought to go in a specific source file (*.cpp):
template <> struct S<int>;
Note: it doesn't "hurt" to have this in every translation unit... other than the time it takes to instantiate by the compiler, and the bloat for the object files (*.o or *.obj).
This is a declaration (the specialization will not be instantiated), and is okay to put in a header file (*.h):
extern template <> struct S<int>;
The declaration requires C++11 or later.
You cannot instantuate a class that is not fully defined in the translation unit. Class template specializations belong in the header file. You can write a function or method specialization in a separate translation unit:
// "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();
}
EDIT:
When the standard says
an explicit specialization shall be defined at most once in a program (according to [basic.def.odr])
it is saying that you cannot have more than one definition according to ODR. The same is true for everything else: you cannot declare two different classes with the same name, so you cannot declare two different specializations with the same template parameters. Putting a class definition in a header file does not violate ODR. Neither does specializing a class template.