C++ Inline functions and template function in header-only library - c++

In order to avoid code bload due to over-inlining...
Is this a valid way to implement a template function that acts
like an inline function?
Original inline function declaration:
inline double MyInlineFunction(){
return 3.141592653589;
}
Alternative function declaration using template function:
template<typename T = void> double MyInlineFunctionT(){
return 3.141592653589;
}

Marking a function inline tells the compiler that it's okay to have the same function defined in more than one translation unit. It's also a hint that the function ought to be expanded inline, but most compilers make their own judgment in that regard. Similarly, a template function can be instantiated in more than one translation unit, and compilers will make their own judgment as to whether to expand it inline.
Short version: there's no difference in code size. But the template version is harder to understand, harder to compile, harder to use, and more likely to produce errors.

Related

C++ templated function overload in cpp

I just wanted to know:
Is it ok to declare a template function (not a member function) in a header such as:
template<class I>
inline I f(const cv::Mat & inMat)
{
throw(std::logic_error("No override found for this type of image"));
}
And then, define what is allowed in the cpp file like this:
template<>
ImageRgbT f<ImageRgbT>(const cv::Mat & inMat)
{
}
I'm trying not to use a specialized class.
You need to declare your specialization in the header:
template<>
ImageRgbT f<ImageRgbT>(const cv::Mat & inMat);
Otherwise, your program is ill-formed NDR according to [temp.expl.spec]/6:
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs; no diagnostic is required.
Violating this rule can cause the compiler to emit one definition for f<ImageRgbT> in one translation unit, instantiated from the primary template, and a different one in the translation unit containing the explicit specialization, leading to linker trouble. It only appears to work in your case because you got lucky and because no diagnostic is required.
Provided that the specialization is declared in the header, there is no problem with defining it in a separate file.

Why does an inline function need pass arguments?

One definition given for an inline function is
If a function is inline, the compiler places a copy of the code of
that function at each point where the function is called at compile
time.
Then my question is: why do we need to pass arguments to an inline function?
E.g
void main()
{
int a = 10;
print(a);
}
inline void print(int a)
{
printf("%d",a);
}
As per the above definition of inline, there should be no compile time errors, as the compiler will translate the code to something like:
void main()
{
int a = 10;
printf("%d",a);
}
Your conclusion is based on an invalid premise. Inline functions are not a macro-like facility that blindly splices the code of the function into the code of the caller. They are a request to the compiler that the function body be inlined if possible, but keeping the normal semantics of the function call/execution. In other words, assuming the code is correct, there should be no observable difference in behavior (other than processor and memory usage, of course) between an inlined and a non-inlined call.
This definition of inline function allows their usage to avoid a number of problems associated with macro, such as clashes of local variables defined in the function with the same name as those in the caller, or calls to function with side effects in the argument (e.g. print(a++) will work correctly with an inline function, but not with a macro).
As a result of this design, the example you provided is a compile-time error.
Inline functions are functions. So they are written and managed like a function.
A compiler may choose to treat these functions differently (may try harder to inline those), but the interface to the user still remains as function.
Moreover it is not guaranteed that inline request would be honored by the compiler.
If you inline a function, it must be defined in each translation unit where it is used and it doesn't give multiple definition link error whether it can be inlined or not by the compiler.
From 7.1.2 Function specifiers [dcl.fct.spec]
A function declaration (8.3.5, 9.3, 11.3) with an inline specifier
declares an inline function. The inline specifier indicates to the
implementation that inline substitution of the function body at the
point of call is to be preferred to the usual function call mechanism.
An implementation is not required to perform this inline substitution
at the point of call; however, even if this inline substitution is
omitted, the other rules for inline functions defined by 7.1.2 shall
still be respected.

What if I declare a big function as inline function?

I search some related questions (such as Benefits of inline functions in C++?), but I still have questions.
If inline function is just to "provide a simple mechanism for the compiler to apply more OPTIMIZATIONS."
Then can I set every function as inline function?
If I wrongfully set a function as inline function, what would happen concerning performance?
Any threshold that tells me what size of function should not be inline function?
Use inline only to satisfy the One Definition Rule. Don't bother with inline for performance reasons.
If inline function is just to "provide a simple mechanism for the
compiler to apply more OPTIMIZATIONS."
If we're talking about the inline keyword, then this is not what inline is about. Like, at all.
All inline does is ensure that a function doesn't violate the One Definition Rule. It might also provide a hint to the compiler that the compiler should blow the code out inline, which may or may not improve speed, but the compiler is entitled to ignore that hint. And in fact in modern compilers they will ignore this hint a great deal of the time.
One of the cases where the compiler is very likely to not blow the code out inline is with big functions. That doesn't mean the function shouldn't be declared inline, however -- it all depends on how the function is declared, defined and used. But, again, it has nothing to do with performance.
Don't try to outsmart the compiler when it comes to applying optimization techniques. It's far better at making your program fast than you are.
Let's see what the Standard has to say on all of this.
7.1.2 Function specifiers
2/A function declaration (8.3.5, 9.3, 11.3) with an inline specifier
declares an inline function. The inline specifier indicates to the
implementation that inline substitution of the function body at the
point of call is to be preferred to the usual function call mechanism.
An implementation is not required to perform this inline substitution
at the point of call; however, even if this inline substitution is
omitted, the other rules for inline functions defined by 7.1.2 shall
still be respected.
This tells us that inline is a request to the compiler to blow the code out inline, and that compilers are not required to perform that substitution. But this also tells us that regardless of the compiler performing this inline substitution, the "other rules" defined in 7.1.2 still apply.
There was a time, long ago, when the optimization techniques employed by C++ compilers were primitive relative to the compilers of today. Back in those days, it might have made sense to use inline as an optimization technique. But these days, compilers are much better at optimizing your code. The compiler applies techniques that, today, would make your code faster than inlining ever would, even if the function isn't actually inlined. (One possible example, RVO.)
So the end result of this is that while the original intent of 7.1.2/2 might have been to give the programmer a manual-optimization technique, modern compilers optimize so aggressively that this original intent is largely moot.
So all that's left for inline are those "other rules." So what are those other rules? (C++11 verbiage)
4/An inline function shall be defined in every translation unit in
which it is odr-used and shall have exactly the same definition in
every case (3.2). [ Note: A call to the inline function may be
encountered before its definition appears in the translation unit. —
end note ] If the definition of a function appears in a translation
unit before its first declaration as inline, the program is
ill-formed. If a function with external linkage is declared inline in
one translation unit, it shall be declared inline in all translation
units in which it appears; no diagnostic is required. An inline
function with external linkage shall have the same address in all
translation units. A static local variable in an extern inline
function always refers to the same object. A string literal in the
body of an extern inline function is the same object in different
translation units. [ Note: A string literal appearing in a default
argument is not in the body of an inline function merely because the
expression is used in a function call from that inline function. — end
note ] A type defined within the body of an extern inline function is
the same type in every translation unit.
Let's take a look at an example. Suppose we have this class template:
File: foo.h
#ifndef FOO_H
#define FOO_H
#include <string>
#include <sstream>
class StringBuilder
{
public:
template <typename T> inline StringBuilder& operator<<(const T& t)
{
mStream << t;
return * this;
}
operator std::string () const;
private:
std::stringstream mStream;
};
StringBuilder::operator std::string() const
{
return mStream.str();
}
#endif
If we #include this file in main.cpp and use the StringBuilder, everything's fine:
File: main.cpp
#include <iostream>
#include <string>
int main()
{
double d = 3.14;
unsigned a = 42;
std::string s = StringBuilder()
<< "d=" << d << ", a=" << a;
std::cout << s << "\n";
}
Output:
jdibling#hurricane:~/dev/hacks$ ./hacks
d=3.14, a=42
But if we want to use the StringBuilder in a second translation unit, we're going to have a problem:
File: other.cpp
#include <iostream>
#include <string>
#include "foo.h"
void DoSomethingElse()
{
unsigned long l = -12345;
long l2 = 223344;
std::string s = StringBuilder()
<< "l=" << l << ", l2=" << l2;
std::cout << s << "\n";
}
Compiler output:
ninja: Entering directory `.'
[1/3] Building CXX object CMakeFiles/hacks.dir/main.o
[2/3] Building CXX object CMakeFiles/hacks.dir/other.o
[3/3] Linking CXX executable hacks
FAILED: : && /usr/bin/g++ -Wall -std=c++11 -g CMakeFiles/hacks.dir/main.o CMakeFiles/hacks.dir/other.o -o hacks -rdynamic -lboost_regex-mt && :
CMakeFiles/hacks.dir/other.o: In function `std::operator|(std::_Ios_Openmode, std::_Ios_Openmode)':
/home/jdibling/dev/hacks/foo.h:21: multiple definition of `StringBuilder::operator std::string() const'
CMakeFiles/hacks.dir/main.o:/home/jdibling/dev/hacks/foo.h:21: first defined here
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
StringBuilder::operator std::string() is defined twice; once in main.cpp and again in other.cpp -- which violated the One Definition Rule.
We can fix this by making the function inline:
class StringBuilder
{
public:
// [...]
inline operator std::string () const;
// ^^^^^^
private:
std::stringstream mStream;
};
Compiler output:
ninja: Entering directory `.'
[1/3] Building CXX object CMakeFiles/hacks.dir/main.o
[2/3] Building CXX object CMakeFiles/hacks.dir/other.o
[3/3] Linking CXX executable hacks
This works because now operator std::string is defined on both translation units with exactly the same definition. It has the same effect as defining the function directly in the declaraton:
class StringBuilder
{
public:
operator std::string () const
{
return mStream.str();
}
private:
std::stringstream mStream;
};
Just because you make a function inline it doesn't mean the compiler has to make it inline. An inline function is a hint to the compiler, not an order.
A compiler will use a set of metrics, such as optimization level, build type (debug or release), code size etc to determine if a function should be inlined.
The basic programming rule for inlining is the function should be of less then 10 lines;
But there is much more on how compiler sees it and what factors you should consider .
https://en.cppreference.com/w/cpp/language/inline
Then can I set every function as inline function?
If you set a really big function as inline it's fully compiler call if it will consider it as an inlining or not same is true for other small functions.
You should not worry about how the compiler optimizes the code.
Istead the advantages there are some disadvantages or declaring big functions as inline or defining them in .h to consider for inlining . For every inline function compiler tries to fit it into the compiler cache , and if the function is too big and you force inlining then there will be cache miss.
If I wrongfully set a function as inline function, what would happen concerning performance?
It's compiler call if it wants to inline it or not you can force it but,
you have __forceinline in windows to forcefully inline
for that also there is no guarantee that functions will be inlined. You can't force the compiler to inline a particular function, even with the __forceinline keyword. When compiling with /clr, the compiler won't inline a function if there are security attributes applied to the function, but use it judiciously as it fully depend on the judgement of the programmer how you want approach it.
https://learn.microsoft.com/en-us/cpp/cpp/inline-functions-cpp?view=vs-2019
Never force it , if you are not sure .
Any threshold that tells me what size of function should not be inline function?
A function larger then 10 lines a basic rule still there is much to consider.
There is by default inlining happening and compiler optimizes as per the defined rules.
The basic rule you should follow for inlining is to define small function in .h inorder to consider them for inlining . Never put large definations in .h files as they can really become an overhead for compiler .
If we assume that a compiler will paste the inline code at the point where the function is called, you would have large chunks of duplicated code.
Functionally, you may observe a negligible performance improvement, but a large increase in the size of your executable.
The primary reason to have the compiler paste the code rather than call the function is when the code in the function is smaller than or close to the overhead costs in calling the function and returning from it. A rule of thumb is a function of a few statements should be marked as inline. As others have stated, the inline keyword is a hint to the compiler, not a request.
Its ultimately complier decision to make function inline or not so if you declare function as inline its just gives a hint to compiler to make this function inline .

Why does inlining template specializations help and should I do it?

The problem with template specializations is that they're treated like normal functions because there is no template parameter used anywhere anymore.
Therefor if the following code is put in a header file it works at first.
template <typename foo>
void f(foo p)
{
std::cout << "f one" << std::endl;
}
template <>
void f<int>(int p)
{
std::cout << "f two" << std::endl;
}
But this stops working if the header is included in two files.
In this case the error I get (with VS2010) is:
templateordering.obj : error LNK2005: "void __cdecl f<int>(int)" (??$f#H##YAXH#Z) already defined in othertu.obj
And this is fixable by using the inline keyword as mentioned in many other questions.
template <>
inline void f<int>(int p)
{
std::cout << "f two" << std::endl;
}
Now this raises two questions for me:
Is there any other way to do this? Putting the specialized function in the source file doesn't seem to work. Probably because I would need some sort of declaration in the header.
What does inline actually do? It seems to be a common rule of thumb all over the internet that inline shouldn't be used because the compiler "will probably inline the function the way he likes in any case". So if the compiler may not inline a function that I declare as "inline", why does this work?
Is there any other way to do this? Putting the specialized function in the source file doesn't seem to work. Probably because I would need some sort of declaration in the header.
You need to declare the specialisation in the header, just like any other function. It's up to you whether to define it inline in the header, or in (exactly one) source file; again, just like any other function. As you say, it must be declared inline if you do define it in the header.
What does inline actually do?
Normally, the one-definition rule requires functions to be defined in exactly one translation unit in the program. In practice this means that you can't define a function in a header, since a header is intended to be included in more than one translation unit.
However, sometimes you want, or need, to define functions in headers - for example, some compilers are only able to inline a function call if they can see the definition. The inline keyword relaxes the rule, so that you can define the function in multiple translation units, as long as all the definitions are identical.
inline enables some changes to the one definition rule. Specifically, a function (including an explicit specialization of a function template) declared inline can be defined in multiple translation units (provided the definitions in different translation units are the same) and must be defined in any translation unit where it is odr-used. This is the same version of the odr rule as applies to function templates (unspecialized).
You either have to define your specialization in one translation unit (and declare it before you use it in other translation units), or you can leave the definition in the header file but make it inline.
A declaration of your specialization would look like this:
template<> void f<int>(int p);
If you use the functions with the same type from two or more files, then the functions will be defined in each file. It's just the same as having a non-template function definition in a header file that is included in multiple source files.
Marking a function as inline hints to the compiler that it can "inline" the function, i.e. put the body of the function directly in place of where the function was called. This means that the function isn't actually defined. The compiler can also decide to not inline the function, in which case the inline keyword behaves like the static keyword.
Is there any other way to do this?
Putting the specialized function in the source file doesn't seem to work. Probably because I
would need some sort of declaration in the header.
Yes, if you separate the declaration and the definition of f<int>, that is supposed to solve the linker error.
The syntax of the declaration in .h file:
template <>
void f<int>(int p);
Is there any other way to do this?
template <>
static void f<int>(int p)
{
std::cout << "f two" << std::endl;
}
or have them inline, but use special compiler flags (where available) to suppress actual inlining
What does inline actually do?
Best answer(s) are already available :)

Normal function not overwriting template function

I have to use an external library, but am getting a "multiple definition error" from following template function and its explicit specialization, if it gets called with a std::string.
template <typename T>
void foo(T& value);
template <>
void foo(std::string& value);
even if I change the 2nd function to
void foo(std::string& value);
the problem is the same.
According to [1] at least the version without a template (the "plain old function") should be prefered over the template version.
Does anybody have a clue, where the problem could be?
[1] http://www.gotw.ca/publications/mill17.htm
You're breaking the one-definition rule.
Unless a function is inline, it can only be defined once. If you mark the function as inline, so long as the definitions match they can be defined as often as desired. Template functions behave as if they were implicitly inline, so you don't get errors with templates.
However, an explicit specialization or non-template function is not implicitly inline and because you're including it in multiple translation units, you get multiple definitions; this breaks the rule. You should mark it as inline:
template <>
inline void foo(std::string& value);
(If you're getting this before link time, you need include guards.)