Does It Make Any Sense to Use Inline Keyword With Templates

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).

inline template function?

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

inline keyword for templates

Is inline necessary to avoid a linker error?

On a function template, no. Templates, like inline functions, are subject to a more relaxed One Definition Rule which allows multiple definitions - as long as the definitions are identical and in separate translation units.

As you say, inline would be necessary if you wanted to define a non-template function in a header; non-inline functions are subject to a more strict One Definition Rule, and can only have one definition in a program.

For the gory details, this is specified by C++11 3.2/5:

There can be more than one definition of a class type, inline function with
external linkage, class template, non-static function template, static data member
of a class template, member function of a class template, or template specialization for
which some template parameters are not specified in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements.

(The "following requirements" basically say that the definitions must be identical).

Benefits of inline functions in templates

A simple test:

#include <math.h>
#include <stdio.h>

template <class T>
class Sine {
public:
#ifdef MAKEINLINE
inline T Eval(T x)
#else // MAKEINLINE
T Eval(T x)
#endif // MAKEINLINE
#ifdef PUTOUTSIDE
;
#else // PUTOUTSIDE
{
return T(sin(double(x)));
}
#endif // PUTOUTSIDE
};

#ifdef PUTOUTSIDE
template <class T>
#ifdef MAKEINLINE
inline T Sine<T>::Eval(T x)
#else // MAKEINLINE
T Sine<T>::Eval(T x)
#endif // MAKEINLINE
{
return T(sin(double(x)));
}
#endif // PUTOUTSIDE

int main(int argc, const char **argv)
{
printf("%g\n", Sine<float>().Eval(M_PI));
printf("%g\n", Sine<double>().Eval(M_PI));
return 0;
}

Running:

g++ Main.cpp -o testi -DMAKEINLINE -O1
g++ Main.cpp -o testn -O1
g++ Main.cpp -o testo -DPUTOUTSIDE -O1
g++ Main.cpp -o testoi -DMAKEINLINE -DPUTOUTSIDE -O1
diff testi testn
diff testi testo
diff testi testoi

Reveals a difference between testi and testo, so as long as the body is inside it does not seem to matter whether it is declared inline, or at least in this simple case and in g++ (GCC) 4.6.4. Note that increasing optimization level inlines all versions of the function and there are no differences.

When should I write the keyword 'inline' for a function/method?

Oh man, one of my pet peeves.

inline is more like static or extern than a directive telling the compiler to inline your functions. extern, static, inline are linkage directives, used almost exclusively by the linker, not the compiler.

It is said that inline hints to the compiler that you think the function should be inlined. That may have been true in 1998, but a decade later the compiler needs no such hints. Not to mention humans are usually wrong when it comes to optimizing code, so most compilers flat out ignore the 'hint'.

  • static - the variable/function name cannot be used in other translation units. Linker needs to make sure it doesn't accidentally use a statically defined variable/function from another translation unit.

  • extern - use this variable/function name in this translation unit but don't complain if it isn't defined. The linker will sort it out and make sure all the code that tried to use some extern symbol has its address.

  • inline - this function will be defined in multiple translation units, don't worry about it. The linker needs to make sure all translation units use a single instance of the variable/function.

Note: Generally, declaring templates inline is pointless, as they have the linkage semantics of inline already. However, explicit specialization and instantiation of templates require inline to be used.


Specific answers to your questions:

  • When should I write the keyword 'inline' for a function/method in C++?

    Only when you want the function to be defined in a header. More exactly only when the function's definition can show up in multiple translation units. It's a good idea to define small (as in one liner) functions in the header file as it gives the compiler more information to work with while optimizing your code. It also increases compilation time.

  • When should I not write the keyword 'inline' for a function/method in C++?

    Don't add inline just because you think your code will run faster if the compiler inlines it.

  • When will the compiler not know when to make a function/method 'inline'?

    Generally, the compiler will be able to do this better than you. However, the compiler doesn't have the option to inline code if it doesn't have the function definition. In maximally optimized code usually all private methods are inlined whether you ask for it or not.

    As an aside to prevent inlining in GCC, use __attribute__(( noinline )), and in Visual Studio, use __declspec(noinline).

  • Does it matter if an application is multithreaded when one writes 'inline' for a function/method?

    Multithreading doesn't affect inlining in any way.

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 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.



Related Topics



Leave a reply



Submit