views:

1744

answers:

8

Suppose I have fileA.h which declares a class classA with template function SomeFunc<T>(). This function is implemented directly in the header file (as is usual for template functions). Now I add a specialized implementation of SomeFunc() (like for SomeFunc<int>()) in fileA.C (ie. not in the header file).

If I now call SomeFunc<int>() from some other code (maybe also from another library), would it call the generic version, or the specialization?

I have this problem right now, where the class and function live in a library which is used by two applications. And one application correctly uses the specialization, while another app uses the generic form (which causes runtime problems later on). Why the difference? Could this be related to linker options etc? This is on Linux, with g++ 4.1.2.

A: 

Unless the specialized template function is also listed in the header file, the other application will have no knowledge of the specialized version. The solution is the add SomeFunc() to the header as well.

Brandon
+4  A: 

Have you added a prototype with parameters to your header file?

I mean is there somewhere in fileA.h

template<> SomeFunc<int>();

If not that's probably the reason.

Serge
A: 

Brandon: that's what I thought - the specialized function should never be called. Which is true for the second application I mentioned. The first app, however, clearly calls the specialized form even though the specialization is not declared in the header file!

I mainly seek enlightenment here :-) because the first app is a unit test, and it's unfortunate to have a bug that doesn't appear in the test but in the real app...

(PS: I have fixed this specific bug, indeed by declaring the specialization in the header; but what other similar bugs might still be hidden?)

oliver
+1  A: 

Per the specs, your specialized function template should never be called outside fileA.C, unless you export the template definition, which no compiler (except Comeau) currently supports (or has it planned for the forseeable future).

On the other hand, once the function template is instantiated, there is a function visible to the compiler that is no longer a template. GCC may re-use this definition across different compiler units because the standard states that each template shall only be instantiated once for a given set of type arguments [temp.spec]. Still, since the template is not exported, this should be limited to the compilation unit.

I believe that GCC may expose a bug here in sharing its list of instantiated templates across compilation units. Normally, this is a reasonable optimization but it should take function specializations into account which it doesn't seem to do correctly.

Konrad Rudolph
A: 

In Microsoft C++, I did an experiment with inline functions. I wanted to know what would happen if I defined incompatible versions of a function in different sources. I got different results depending on whether I was using a Debug build or a Release build. In Debug, the compiler refuses to inline anything, and the linker was linking the same version of the function no matter what was in scope in the source. In Release, the compiler inlined whichever version had been defined at the time, and you got differing versions of the function.

In neither case were there any warnings. I kind of suspected this, which is why I did the experiment.

I assume that template functions would behave the same, as would other compilers.

Mark Ransom
+6  A: 

It is an error to have a specialization for a template which is not visible at the point of call. Unfortunately, compilers are not required to diagnose this error, and can then do what they like with your code (in standardese it is "ill formed, no diagnostic required").

Technically, you need to define the specialization in the header file, but just about every compiler will handle this as you might expect: this is fixed in C++0x with the new "extern template" facility:

extern template<> SomeFunc<int>();

This explicitly declares that the particular specialization is defined elsewhere. Many compilers support this already, some with and some without the extern.

Anthony Williams
A: 

@[anthony-williams],

are you sure you're not confusing extern template declarations with extern template instantiations? From what I see, extern template may only be used for explicit instantiation, not for specialization (which implies implicit instantiation). [temp.expl.spec] doesn't mention the extern keyword:

explicit-specialization:
    template < > declaration

Konrad Rudolph
Damnit, the automatic linking of the user name doesn't work.
Konrad Rudolph
+2  A: 
SOB that was formatted in the preview! sorry