Question

Consider the following minimal example which reproduces a problem in a much bigger project:

spec.h:

#include <iostream>

class A
{
public:
    template<typename T>
    T test(const std::string& a)
    {
        std::cout << "DEFAULT CALLED WITH " << a << "\n";
        return T();
    }
};

other.cpp:

#include "spec.h"

template<>
float A::test<float>(const std::string& a)
{
    std::cout << "SPECIAL CALLED WITH " << a << "\n";
    return float();
}

spec.cpp:

#include <iostream>
#include "spec.h"

int main()
{
    A a;
    a.test<int>("int");
    a.test<float>("float");
    return 0;
}

compilation:

$ 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

question:

Why is this happening? is it getting stripped somehow? what is the difference between lib.a and direct object file usage? :-)

Thanks!

Was it helpful?

Solution

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.

OTHER TIPS

Ben Voigt's answer is correct, but I want to add a little to it.

You are essentially getting two different versions of the function, one in other.o and one in spec.o (generated by the inline template). The linker is designed to choose one and only one, making the assumption that they're both identical as the standard requires. In the first case, the linker will only pull a definition from a library if the symbol isn't already defined. Since it's defined in spec.o the library definition isn't used.

With the definition in the header each translation unit can create its own instantiation. Thus, there is never an undefined symbol referencing your specialized version. Correspondingly, the object file with the specialized version isn't included when looking at the library: it doesn't define any undefined symbol. When including the object file explicitly while linking, the linker has no choice than including it. However, you need to declare all specializations: without the declaration the compiler has no clue that the general version isn't applicable. What happens do this version, whether it is used or not, thus, depends on the way the symbol is treated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top