Question

The problem with template specializations is that they're treated like normal functions because there is no template parameter used anywhere anymore.

Therefor if the following code is put in a header file it works at first.

template <typename foo>
void f(foo p)
{
  std::cout << "f one" << std::endl;
}

template <>
void f<int>(int p)
{
  std::cout << "f two" << std::endl;
}

But this stops working if the header is included in two files. In this case the error I get (with VS2010) is:

templateordering.obj : error LNK2005: "void __cdecl f<int>(int)" (??$f@H@@YAXH@Z) already defined in othertu.obj

And this is fixable by using the inline keyword as mentioned in many other questions.

template <>
inline void f<int>(int p)
{
  std::cout << "f two" << std::endl;
}

Now this raises two questions for me:

  1. Is there any other way to do this? Putting the specialized function in the source file doesn't seem to work. Probably because I would need some sort of declaration in the header.
  2. What does inline actually do? It seems to be a common rule of thumb all over the internet that inline shouldn't be used because the compiler "will probably inline the function the way he likes in any case". So if the compiler may not inline a function that I declare as "inline", why does this work?
Was it helpful?

Solution

Is there any other way to do this? Putting the specialized function in the source file doesn't seem to work. Probably because I would need some sort of declaration in the header.

You need to declare the specialisation in the header, just like any other function. It's up to you whether to define it inline in the header, or in (exactly one) source file; again, just like any other function. As you say, it must be declared inline if you do define it in the header.

What does inline actually do?

Normally, the one-definition rule requires functions to be defined in exactly one translation unit in the program. In practice this means that you can't define a function in a header, since a header is intended to be included in more than one translation unit.

However, sometimes you want, or need, to define functions in headers - for example, some compilers are only able to inline a function call if they can see the definition. The inline keyword relaxes the rule, so that you can define the function in multiple translation units, as long as all the definitions are identical.

OTHER TIPS

inline enables some changes to the one definition rule. Specifically, a function (including an explicit specialization of a function template) declared inline can be defined in multiple translation units (provided the definitions in different translation units are the same) and must be defined in any translation unit where it is odr-used. This is the same version of the odr rule as applies to function templates (unspecialized).

You either have to define your specialization in one translation unit (and declare it before you use it in other translation units), or you can leave the definition in the header file but make it inline.

A declaration of your specialization would look like this:

template<> void f<int>(int p);

If you use the functions with the same type from two or more files, then the functions will be defined in each file. It's just the same as having a non-template function definition in a header file that is included in multiple source files.

Marking a function as inline hints to the compiler that it can "inline" the function, i.e. put the body of the function directly in place of where the function was called. This means that the function isn't actually defined. The compiler can also decide to not inline the function, in which case the inline keyword behaves like the static keyword.

Is there any other way to do this? Putting the specialized function in the source file doesn't seem to work. Probably because I would need some sort of declaration in the header.

Yes, if you separate the declaration and the definition of f<int>, that is supposed to solve the linker error.

The syntax of the declaration in .h file:

template <>
void f<int>(int p);

Is there any other way to do this?

template <>
static void f<int>(int p)
{
  std::cout << "f two" << std::endl;
}

or have them inline, but use special compiler flags (where available) to suppress actual inlining

What does inline actually do?

Best answer(s) are already available :)

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