Reputation: 7921
I have a header containing a class with a template member and some specialisations of that member:
#include <iostream>
class Foo {
public:
template<typename T>
void print(const T& t) {
std::cout << t << std::endl;
}
};
template<>
void Foo::print<int>(const int& t) {
std::cout << t << std::endl;
}
This header is included in multiple source files.
If I put the specialisation inside the class definition, then GCC complains:
error: explicit specialization in non-namespace scope ‘class Foo’
But if I move the specialisation outside the class definition, then VC++ complains about multiply-defined symbols.
What's the right way of doing this that both compilers will be happy with?
Upvotes: 1
Views: 75
Reputation: 320371
An explicitly specialized template function is no longer a template (it no longer depends on any template parameters). As such it obeys the One Definition Rule as an ordinary function. This means that the definition of an explicitly specialized function should be made once and only once in the entire program. I.e. you have to place the definition into an implementation file (.cpp
file).
However, you still have to declare this specialization in the header file (to tell the compiler that it actually exists). I.e. in the header file you have to do
template<>
void Foo::print<int>(const int& t);
(Note that per standard requirements it should be done in namespace scope, i.e. outside of the class definition.)
Then in one implementation file you do
template<>
void Foo::print<int>(const int& t) {
std::cout << t << std::endl;
}
P.S. Of course, just as with any other function, you can declare it inline
and keep the definition in the header file.
Upvotes: 6
Reputation: 60969
The standard says (§14.7.3/12):
An explicit specialization of a function template is inline only if it is declared with the inline specifier or defined as deleted, and independently of whether its function template is inline.
A specialization of a function template is treated by the ODR like a normal function (no specialization).
If you define the specialization inside the header, you have to declare it with the inline
specifier, so several translation units can include it.
If you want to define it in the source file, you have to declare the specialization inside the header (at namespace scope):
template<>
void Foo::print<int>(const int&);
And put the definition in the source file
template<>
void Foo::print<int>(const int& t)
{
std::cout << t << std::endl;
}
, just as you're used to with normal functions.
Upvotes: 0