oliver
oliver

Reputation: 6771

Visibility of template specialization of C++ function

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.

Upvotes: 25

Views: 9038

Answers (9)

Anthony Williams
Anthony Williams

Reputation: 68571

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++11 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.

Upvotes: 23

CarLuva
CarLuva

Reputation: 650

As Anthony Williams says, the extern template construct is the correct way to do this, but since his sample code is incomplete and has multiple syntax errors, here's a complete solution.

fileA.h:

namespace myNamespace {
  class classA {
    public:
      template <class T> void SomeFunc() { ... }
  };

  // The following line declares the specialization SomeFunc<int>().
  template <> void classA::SomeFunc<int>();

  // The following line externalizes the instantiation of the previously
  // declared specialization SomeFunc<int>(). If the preceding line is omitted,
  // the following line PREVENTS the specialization of SomeFunc<int>();
  // SomeFunc<int>() will not be usable unless it is manually instantiated
  // separately). When the preceding line is included, all the compilers I
  // tested this on, including gcc, behave exactly the same (throwing a link
  // error if the specialization of SomeFunc<int>() is not instantiated
  // separately), regardless of whether or not the following line is included;
  // however, my understanding is that nothing in the standard requires that
  // behavior if the following line is NOT included.
  extern template void classA::SomeFunc<int>();
}

fileA.C:

#include "fileA.h"

template <> void myNamespace::classA::SomeFunc<int>() { ... }

Upvotes: 1

Brandon
Brandon

Reputation: 714

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<int>() to the header as well.

Upvotes: 0

Aaron
Aaron

Reputation:

I had the same problem with gcc4, here is how i solved it. It was more simple a solution than what i was lead to believe by previous comments. The previous posts ideas were correct but their syntax didn't work for me.


    ----------header-----------------
    template < class A >
    void foobar(A& object)
    {
      std::cout << object;
    }

    template <> 
    void foobar(int);

    ---------source------------------
    #include "header.hpp"

    template <>
    void foobar(int x)
    {
      std::cout << "an int";
    }

Upvotes: 3

Konrad Rudolph
Konrad Rudolph

Reputation: 545588

@[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

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308138

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.

Upvotes: 1

Konrad Rudolph
Konrad Rudolph

Reputation: 545588

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.

Upvotes: 2

oliver
oliver

Reputation: 6771

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?)

Upvotes: 0

Serge
Serge

Reputation: 7694

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.

Upvotes: 9

Related Questions