Consider the following minimal example which reproduces a problem in a much bigger project:
#include <iostream>
class A
{
public:
template<typename T>
T test(const std::string& a)
{
std::cout << "DEFAULT CALLED WITH " << a << "\n";
return T();
}
};
#include "spec.h"
template<>
float A::test<float>(const std::string& a)
{
std::cout << "SPECIAL CALLED WITH " << a << "\n";
return float();
}
#include <iostream>
#include "spec.h"
int main()
{
A a;
a.test<int>("int");
a.test<float>("float");
return 0;
}
$ make
rm -f *.o lib.a output
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
ar cr lib.a other.o
clang++ -g -o output lib.a spec.o
rm -f *.o output2
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
clang++ -g -o output2 other.o spec.o
$ ./output
DEFAULT CALLED WITH int
DEFAULT CALLED WITH float
$ ./output2
DEFAULT CALLED WITH int
SPECIAL CALLED WITH float
Why is this happening? is it getting stripped somehow? what is the difference between lib.a and direct object file usage? :-)
Thanks!
From section 14.7.3p6:
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required.
Your program is ill-formed because you used the specialization in spec.cpp without declaring it first in that translation unit. Or, as the following paragraph says:
The placement of explicit specialization declarations for function templates, class templates, member functions of class templates, static data members of class templates, member classes of class templates, member enumerations of class templates, member class templates of class templates, member function templates of class templates, member functions of member templates of class templates, member functions of member templates of non-template classes, member function templates of member classes of class templates, etc., and the placement of partial specialization declarations of class templates, member class templates of non-template classes, member class templates of class templates, etc., can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below.
When writing a specialization
be careful about its location;
or to make it compile
will be such a trial
as to kindle its self-immolation.
which I vote for as the awesomest paragraph limerick in the whole Standard.