Inline specializations and multiple inclusions

Recently, I came across a problem being faced by an individual on the forums. He had the code like this:

[CODE]
//file: header.h
#ifndef HEADER_H
#define HEADER_H

#include <iostream>

template<class T>
void foo(T val){
    std::cout << "foo<T>("<<val<<")\n";
}
template<>
inline void foo(double val){
    std::cout << "foo<double>(" << val <<")\n";
}

#endif

//file: main.cpp
#include "header.h"

int main(){
    double x=4;
    foo(x);
    return 0;
}

//file: other.cpp
#include "header.h"
void somecode(){}

Just to summarize the above code, there is a header file (header.h) that contains the template functions and its specialization on type 'double' for template type parameter declared inline. And that header is being included into 2 implementation files (main.cpp & other.cpp)

This code compiled fine for him but as soon as he removed the inline keyword, it started to given him linker error for multiple definitions of the foo<double> function. We might start wondering what is it between templates and inline that might be causing this? Something and nothing. What happens is explained below:

The linker error seen is not specific to templates or specializations. One will face the same problem if they turned foo into a non-template function. C++ functions have external linkage hence they must be implemented in just one .cpp file (implementation file). They can, however, be declared multiple times. When we provide the implementation in the header file instead of an implementation file and that header is being included multiple implementation files (main.cpp and other.cpp), we have multiple definitions and hence, rightly the linkage error. Putting the implementation into the header file was what we were forced to do when using a template function because we need to put the implementation in the header file as well as the declaration since 'export' doesn't work except for just with the Comeau compiler. But specializations are a different case than regular templates. We don't face such issues with regular templates (not their specializations) because the instantiation rules guarantees that there is just one copy of the function generated as and when needed. While in case of specializations, we end up with multiple definitions because of them being included into multiple implementation files.

Now, with inline functions, we provide the implementation in the header file so as to be visible to the compilation point where they are used. They become inline in the final executable or not is irrelevant. You just follow the rule to define the inline functions. There will be only one copy of them.

Coming to the solutions to the above linker error, below are the two simplest ways:

1. Make the specialization as inline (as in original code, in case, someone facing this issue didn't have it in the first place)

2. Declare it not as a specialization but just as an overloaded foo function and declare it in the header (header.h) and provide implementation in an implementation file (for that matter any one implementation main.cpp/other.cpp or a .cpp of its own for header.h templates' specializations just making sure we don't do it twice).

References:

1. Codeguru thread where I came across this - "inline" and linking errors
2. C++ FAQ Lite on Inline Functions

Check out this stream