Inlining Template Specialization

Inlining Template Specialization

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.

Why do templates specialisations need to be inlined?

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.

C++ inline or not inline declarations of template class specializations

Like the other Q&A mentions, the specialization is its own entity. If you do as you did, declare the specialization in a header, and then define them in another (single) TU, that is well-formed. Any TU that includes that header will see that the specialization for int and float are only declarations. As such, their definition may be placed elsewhere, just like a non-template function.

If you want a header only library, where the specialized functions are defined inline, then you must use the inline specifier, as the ODR requires.

Neither way is "the correct" way in the sense you seem to be asking about. Each has its own advantages and disadvantages. Defining the functions inline helps make libraries be header only. But if the functions are complex, then all of their dependencies are pulled into every TU that includes the header. Also, changing the specializations will cause all of those TU's to be re-compiled. So there's merit for tucking the implementation away too at times. You'll need to judge on a case by case basis.

Inlining a function template specialization

Because explicit specializations are definitions and so including that file in multiple translation units results in defining the symbol multiple times, which breaks the one definition rule.

Besides marking it inline, you can leave the declaration in the header and move the definition to an implementation file.

Having different specialization of a class template and the specialization definitions have functions with other specializations in its signature

An explicit specialization is a distinct class and does not have to resemble the original template at all. You can change the functions, make completely different ones, or whatever.

This is usually the point of partial specialization, so a const T can be a different interface than a plan T etc.

Any explicit specializations must be declared before that specialization is used. That's why you get redeclaration errors.

Also, you showed <float> twice, I assume that's a paste error? The one in Double.h should be <double> right?

You violated that with your circular reference. You can fix that by declaring the one you need (without defining it), similarly to how you do with mutually recursive functions.

Here is the correctly-compiling and running code: https://godbolt.org/z/x1TcTE7Me

You'll notice that the definition of

//template<>      // Don't use the `template<>` prefix here!!!
inline void Something<float>::SayDouble(Something<double> p_D) {
std::cout << p_D.Name << '\n';
}
// I'm showing it with `inline` in case you put it in a header. It can go in
// some CPP file though, as it's been declared in the class specialization.

does not use the template prefix. That's because this is defining a member function (that's not a template) for a class just like a normal class — the explicit (and not partial) specialization is a normal class like any other, not a template. It just says "when I ask for this specialization of that template, use this class instead of generating one".

Finally, the parameter name _D is not allowed. "If the programmer uses such identifiers, the behavior is undefined."

Defined `inline` Template Method Isn't Found for Specialization

Why does this happen?

Because you didn't define it. A full specialization of a class template essentially produces a "regular" class definition. You can add, omit or modify the members of the class.

What it also means is that it doesn't get anything from the primary template "automagically". You need to provide it explicitly. And since you didn't provide

inline Foo<1>::Foo() {} // Note how we don't need template<> here? Like a regular class

There is no such c'tor.

As for the "works happily" addendum you posted, it doesn't matter. When you don't define an entity that is used by your program, it's a violation of the one definition rule. Formally, your program is ill-formed no diagnostic required. Which means the behavior is undefined, and implementations are free to mess with your compiled program as they see fit.

Be thankful the better compilers of the bunch let you know you messed up, instead of gliding over the issue.

Template specialization of operator[] within a class with multiple template parameters

As your operator[] is not a template, you can't specialize it inside your class. What you want is to specialize the non template method for a template class.

But you can't do a partial specialization for the class to add definitions of members to it.

Working example:

template <class stringT = std::string, class delimiterT = char>
class Tokenizer
{
const std::string& operator[](size_t tokenIndex);
};

template<>
inline const std::string& Tokenizer<std::wstring, char>::operator[](size_t )
{
return emptyString;
}
template< >
inline const std::string& Tokenizer<std::string, char>::operator[](size_t )
{
return emptyString;
}

To get rid of that problem you should check if your method really depends on all template parameters. If not, you can simply put them to a base class, which only depends on a single template parm and inherit from there. Maybe other code organization may also help.



Related Topics



Leave a reply



Submit