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.
.tpp
. That's a very posh programming style. Upvoted the question for that. Are you targetting a particular C++ standard? Templates are moving quite quickly at the moment. – Negrito