inline vs. constexpr?
-
29-12-2020 - |
Question
With the new C++11 standard, when should I use the inline
keyword over the constexpr
keyword? Does the constexpr
keyword offer any additional optimization over inline
, or does it merely assert that things must be computed at compile-time?
Why does constexpr
work on the GCC in some cases where the call is not constant, such as calling foo(x)
on a non-constexpr
variable? Is this a bug in the GCC or is it actually part of the standard?
Solution
Asserting that something can be computed at compile-time is a pretty strong kind of optimization.
Inlining merely removes a function call, by copy/pasting the function body into the call site. The function body still has to be executed, you just save the overhead of a function call.
But if you make the same code be evaluated at compile-time, it is free at runtime.
But neither inline
nor constexpr
are primarily about optimization. inline
's main purpose is to suppress the one-definition-rule, so that functions can be defined in headers (which is useful for templates, and incidentally, also makes the inlining optimization easier)
And constexpr
is there because it is useful in metaprogramming, and incidentally, it may help the compiler better optimize the code, by moving more computations to compile-time.
OTHER TIPS
To quote wikipedia:
C++0x will introduce the keyword constexpr, which allows the user to guarantee that a function or object constructor is a compile-time constant.
Mark functions inline if they are super short. Mark functions as constexpr if the results are required at compile time. (Template parameters or array sizes). I believe a function can be both if needed.
A constant expression function or constructor can be called with non-constexpr parameters. Just as a constexpr integer literal can be assigned to a non-constexpr variable, so too can a constexpr function be called with non-constexpr parameters, and the results stored in non-constexpr variables. The keyword only allows for the possibility of compile-time constancy when all members of an expression are constexpr.
So, GCC is not incorrect in this.
While inline
says to the compiler "This function is used somewhere in this translation unit and is not public to other object files", it is likely that the compiler inserts the body of the function into the caller. constexpr
functions say to the compiler "This function has no side effects and does not depend on preconditions other than the parameter itsself."
constexpr
variables just say "This variable does not change and its data can be included into the code.". However it makes a difference if you define a constexpr variable in a function static or nonstatic, eg. if a constexpr
array is nonstatic, gcc just moves the data with hardcoded mov
-instructions onto the stack, while static constexpr
just stores the data in the .text
-section.
Lambda expressions without capture assigned to a variable can be constexpr other than with capture, because without they need no memory to save the capture and they work like an empty class with overloaded operator()
(but they can even be casted to plain function pointers with a simple unary plus: +[]{}
).