Why do templates specialisations need to be inlined?
Asked Answered
A

3

14

I am referring to this answer:

https://mcmap.net/q/543057/-template-specialization-multiple-defined-symbols

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?

Anglaangle answered 23/1, 2018 at 13:12 Comment(6)
What's the "why" you are after? Something that points at what the C++ standard says, or the rationale for it?Lombardi
.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
@StoryTeller yeah -- why do I need to include the explicit inline? My guess is that its because template functions can be considered to be inline, but again I am declaring my function to be a specialised template?Anglaangle
Well, the idea is that a function template specialization is no longer a template - all template parameters are known, so it is compiled like a regular function. I'm trying to look up relevant standard quotes.Aligarh
Not to be rude, but I asked you an "OR" question, and you responded with "yes".Lombardi
@StoryTeller. Sorry about this -- I had the "rationale" part in mind.Anglaangle
G
7

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.

Globigerina answered 23/1, 2018 at 13:58 Comment(0)
L
10

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.

Lombardi answered 23/1, 2018 at 13:33 Comment(0)
H
8

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

Heavenward answered 23/1, 2018 at 13:33 Comment(0)
G
7

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.

Globigerina answered 23/1, 2018 at 13:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.