问题
If I have a header foo.h which I include all over my project, it seems to work fine when all it contains is:
template<typename T>
void foo(const T param) {
cout << param << endl;
}
But I get one definition rule (ODR) errors when I add a specalization to foo.h:
template<>
void foo(const bool param) {
cout << param << endl;
}
Obviously I can solve this by inline
'ing the specialization. My question is, why do I need to? If the template doesn't violate ODR, why does a specialization?
回答1:
An explicit specialization is not implicitly inline. It must be explicitly made inline.
[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 ]
So you have to do it, because the standard says you have to do it.
回答2:
The reason why templates are exempt from ODR is simply that there is no other choice.
A template is not a "tangible end-product" from compiler's perspective. The implementation of templates must be carried around so that it can be expanded into compilable code when used. As a result, it must reside in a header file, and duplicate definitions from different compilation units are consequent and unavoidable. Since it is unavoidable, the standard makes a compromise to exempt them from ODR.
A function is an end-product that can be readily compiled into target code, so compilers hate to see potentially conflicting definitions, even if it is entirely possible to compare the codes and proceed if the codes are identical. However, the compilers decide they are way too lazy to do such extra check, and hence the standard banned multiple definitions.
Now, an explicit/full specialization of a template function is de facto a function, not a template - as all the missing pieces have been filled and there is no need to carry the definition of the specialized function around anymore. In contrast, a partial specialization is de facto a template, as its implementation still needs to be carried around during compilation. Therefore, partial template specializations enjoy the exempt inherited from templates, whereas explicit/full specializations don't.
来源:https://stackoverflow.com/questions/51987423/inlining-template-specialization