Inlining Template Specialization
Asked Answered
H

2

8

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?

Hitandmiss answered 23/8, 2018 at 13:50 Comment(9)
A specialisation of a template function is a definition, if the body is defined.Drowsy
related/dupe: #10536167Ramires
@Ramires Yeah I looked at that one... it doesn't address specialization. I was really just hoping for something official saying I had to inline. Looks like StoryTeller has got me.Hitandmiss
@JonathanMee It doesn't? What about in the middle of the answer under tpl.h (taken from Explicit Specialization): that has the exact same code block?Ramires
@Ramires Heh... well look at that. I only looked at the question :/ I wouldn't mind duping this. Since it's well answered over there. What do you think?Hitandmiss
BTW, overloading is generally better than specialization.Shanteshantee
@Shanteshantee Can you explain further? Why is it generally better?Hitandmiss
@JonathanMee - Her's an SO post chewing it out #7108533Perceptive
@Shanteshantee I was looking into this further and found this excellent write up, so I thought I'd share it here: gotw.ca/publications/mill17.htm Thanks for pointing me in the right direction.Hitandmiss
P
15

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.

Perceptive answered 23/8, 2018 at 13:56 Comment(0)
F
4

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.

Fillet answered 23/8, 2018 at 14:18 Comment(1)
template are not exempt of ODR, token should be identical, resulting instantiation should "behave" identically (visible function for ADL, ...). It just doesn't require inline keyword.Shanteshantee

© 2022 - 2024 — McMap. All rights reserved.