Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

templates

I've recently run into a situation while specializing templates that has made me uneasy:

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 compile as follows:

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

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

Here's what I think gcc is doing: When main.cc is compiled, I would expect it to emit the generic code for the foo call because it is not aware of the specialization in foo.cc. But by linking with foo.o, it uses the specialization instead because it has the same signature.

But is this bad to count on? I'm worried that other compilers (or maybe even different versions of gcc?) might mangle their signatures when they emit template code, in a way that linking with foo.o will not replace the generic action like I want it to. Is this a valid worry? I've read a lot of things that make me feel uneasy, but nothing that makes me feel confident about what is happening in my current situation.

like image 850
user2117521 Avatar asked Feb 28 '13 00:02

user2117521


1 Answers

I'm worried that what I'm observing might be unique to gcc (I don't have access to other compilers so I can't check).

You have good reasons to be worried: Your program is ill-formed, and the compiler is not even required to tell you!

Paragraph 14.7.3/6 of the C++11 Standard specifies:

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. An implicit instantiation is never generated for an explicit specialization that is declared but not defined

Your specialization must be visible from the point of instantiation in order for the program to have consistent behavior. In your case, it isn't: you are relegating it in a file which is not included by other translation units.

Paragraph 14.7.3/7 Standard is quite explicit about what happens when you fail to do this:

The placement of explicit specialization declarations for function templates, class templates, member functions of class templates, [...], 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.

I guess the last sentence makes it clear.

Here, what you should do is to declare your intention to introduce an explicit specialization of your function template before any implicit instantiation of the primary template would occur. To do so, 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 introducing a declaration right after the definition of the primary template, you make sure that wherever the primary template is visible, it will be known that a full specialization for it exists, saving you from self-immolation.

like image 118
Andy Prowl Avatar answered Oct 07 '22 18:10

Andy Prowl