I am referring to this answer:
https://stackoverflow.com/a/4447057/930315
I ran into a similar issue as the OP of the cited question,
having a function
template<typename T>
void func(T& val);
and its specialization
template<>
void func<mytype>(mytype& val);
resulted in a duplicate symbols linker error (the methods are implemented in a '.tpp' file that is included at the end of my header).
adding inline
to the specialised function resolved the issue. Why?
According to clause 3.2:4 in the c++ standard
Every program shall contain exactly one definition of every non-inline
function or variable that is odr-used in that program; no diagnostic
required. The definition can appear explicitly in the program, it can
be found in the standard or a user-defined library, or (when
appropriate) it is implicitly defined (see 12.1, 12.4 and
12.8). An inline function shall be defined in every translation unit in which it is odr-used.
This explains why there is a link-time error when the specialized function is not declared inline. The program will contain multiple definitions of the specialized function, one from each module including the .tpp-file and this breaks the condition from the standard. When declaring the specialized function inline
it will make the function satisfy the second part of the same clause, i.e. that an inline function must be defined in each module using the function.
When the parameterized function is not specialized it is covered by clause 3.2:6:
There can be more than one definition of a class type (Clause 9),
enumeration type (7.2), inline function with external linkage (7.1.2),
class template (Clause 14), non-static function template (14.5.6),
static data member of a class template (14.5.1.3), member function of
a class template (14.5.1.1), or template specialization for which some
template parameters are not specified (14.7, 14.5.5) in a program
provided that each definition appears in a different translation unit
This clause states that it is OK for multiple definitions of the same template function as long as at least one of the template parameters is not specified in the code. This is to allow the decision on whether the parameterized function should be instantiated in a module to be made on local information only.
Well, if you want the standard quote on this, that'd be over at [temp.expl.spec]/12
An explicit specialization of a function or variable template is
inline only if it is declared with the inline specifier or defined as
deleted, and independently of whether its function or variable
template is inline. [ Example:
template<class T> void f(T) { /* ... */ }
template<class T> inline T g(T) { /* ... */ }
template<> inline void f<>(int) { /* ... */ } // OK: inline
template<> int g<>(int) { /* ... */ } // OK: not inline
— end example ]
That's why you have to do it. It's independent because I believe doing otherwise would be needlessly restrictive, as Yola demonstrated.
This will work without inline:
file1.h
template<typename T> void func(T& val);
template<> void func<mytype>(mytype& val);
file1.cpp
template<> void func<int>(int& ) {}
But if you define template specialization in header file, than you may violate ODR