Do all compilers ignore the generated template code when explicit specializations are available to the linker?

I recently came across a situation specializing in patterns that made me awkward:

foo.h:

template <class T> void foo() { std::cout << "This is the generic foo" << std::endl; } 

foo.cc:

 #include "foo.h" template <> void foo<int>() { std::cout << "This is foo<int>" << std::endl; } 

main.cc:

 #include "foo.h" int main() { foo<int>(); } 

So. I am compiling the following:

 g++ -c main.cc g++ -c foo.cc g++ -o main main.o foo.o 

The output signal is "This is foo<int>" . I like this outlet. But I'm worried that what I am observing may be unique to gcc (I don't have access to other compilers, so I can't verify).

Here's what I think gcc does: When main.cc is compiled, I expect it to produce a generic code for calling foo because it does not know the specialization in foo.cc. But when contacting foo.o, it uses specialization instead, because it has the same signature.

But what is it bad to count on? I am worried that other compilers (or maybe even different versions of gcc?) May cripple their signatures when they emit a code template so that linking to foo.o does not replace the general action as I want it to. Is this a compelling concern? I read a lot of things that make me feel uncomfortable, but nothing that makes me feel confident about what is happening in my current situation.

+6
source share
1 answer

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>(); // Introduce a declaration of your // explicit specialization right // after you defined the primary // template! 

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.

+8
source

All Articles