C++ Template and Inline

inline template function?

You do, because those are full function specializations, and therefore subject to the one-definition rule just like normal functions.

Does it make any sense to use inline keyword with templates?

It is not irrelevant. And no, not every function template is inline by default. The standard is even explicit about it in Explicit specialization ([temp.expl.spec])

Have the following:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (taken from Explicit Specialization):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

Compile this, et voila:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

Not stating inline when doing explicit instantiation may also lead to issues.

So in summary: For non fully specialized function templates, i.e. ones that carry at least one unknown type, you can omit inline, and not receive errors, but still they are not inline. For full specializations, i.e. ones that use only known types, you cannot omit it.

Proposed rule of thumb: Write inline if you mean it and just be consistent. It makes you think less about whether to or not to just because you can. (This rule of thumb is conforming to Vandevoorde's/Josuttis's C++ Template: The Complete Guide).

C++ template and inline

Templated functions as far as I know are automatically inline. However, the reality is that most modern compilers regularly ignore the inline qualifier. The compiler's optimizing heuristics will most likely do a far better job of choosing which functions to inline than a human programmer.

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.

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.

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.

Inline Lambda variable vs Inline function vs Inline template function with automatic type deduction

They all 3 define something sightly different. Hence, answer to 2 is: Choose the one that does what you want. 1) I'll levave to you, because you can easily try them out to see if they compile. 3) isn't that relevant, because choosing between them is a matter of what you actually need, not of style.

inline auto const myfunc = [&](const auto& val){return something(val);};

The lambda myfunc is of some unnamed type with a templated operator(). myfunc itself is not templated. You can pass myfunc to other functions, because it is an object. You cannot do that easily with the other two.

The difference between

inline auto myfunc(const auto& val)
{
return something(val);
}

and

template<class T>
inline T myfunc(const T& val)
{
return something(val);
}

is the return type. With the second, the return type is T. T is either deduced from the paramter or you specify it explicitly and then it can be different from the parameter passed, as long as the parameter can convert to const T&. Hence the first is more similar to the lambda (more precisely, to its operator()), because the return type is deduced from something(val), though the lambda additionally captures via &. You cannot do that easily with a function.



Related Topics



Leave a reply



Submit