I am worried that what I am observing may be unique to gcc (I do not have access to other compilers, so I cannot verify).
You have good reason to worry: your program is poorly formed, and the compiler does not even have to tell you!
Clause 14.7.3 / 6 of C ++ 11 Standard states:
If the template, element template, or member of the class template is explicitly specialized, then this specialization must be declared before the first use of this specialization, which will lead to an implicit instance to occur, in each translation unit in which such use occurs; no diagnostics required. If the program does not provide a definition for explicit specialization, and either specialization is used in such a way that leads to an implicit instance creation or a member is a virtual member function, the program is poorly formed, and diagnostics are not required . Implicit instantiation is never generated for an explicit specialization that is declared but not defined
Your specialization should be visible from the moment of creation, so that the program has consistent behavior. In your case, this is not so: you drop it into a file that is not included in other translation units.
Paragraph 14.7.3 / 7 The standard is pretty clear about what happens when you do not:
Placing explicit specialization declarations for function templates, class templates, member functions of class templates, [...] can affect whether the program is well-formed in accordance with the relative location of explicit specialization descriptions and their points in the translation block, as indicated above and below. When writing a specialization, be careful about its location; or make it a compilation, will be such a test to rekindle its self-immolation.
I think the last sentence makes it clear.
Here you need to declare your intention to explicitly specialize the function template before implicitly creating the primary template. To do this, do the following:
foo.h
template <class T> void foo() { std::cout << "This is the generic foo" << std::endl; } template <> void foo<int>();
By entering the announcement immediately after defining the primary template, you will see that wherever the primary template is seen, it will be known that there is a complete specialization for it, which saves you from self-immolation.