inline vs. constexpr?
Asked Answered
E

3

52

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?

Enceinte answered 18/8, 2011 at 20:40 Comment(0)
O
58

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.

Overthrow answered 18/8, 2011 at 20:59 Comment(9)
According to this question, when constexpr functions are not used in a context requiring a constant expression, the compiler is not obligated to compute the expression at compile-time.Cribble
but it still specifies that the computation can be performed at compile-time. So as with inline, it's not really about optimization, but it may provide additional information that the compiler can use to optimize.Overthrow
Right, I was just nitpicking about use of the word "must". :-]Cribble
@jalf I'd disagree that inline is not primarily about optimization. IIRC functions defined in a header file default to being inlined, though as is always the case with inline - it's merely a compiler hint. As long as you've got header guards in place then ODR isn't really relevant anyway. Willing to be educated here though :-)Grille
@Grille wrong: a missing inline in a header will violate the ODR: two source files using the same non-inline function defined in the header will cause a multiple definition error when linking them together. It is exactly inline that fixes that.Azaleah
@boycy: ODR has nothing to do with header guards. (The ODR is about multiple translation units defining the same symbol. Header guards protect against multiple definitions inside the same translation unit). And the compiler will inline whatever it feels like, regardless of the inline keyword. It can inline things that aren't marked inline and it is not required to inline that which you mark inline. So optimization-wise, the keyword doesn't really do anything.Overthrow
Where optimization enters into the picture is that if you mark something inline, then you can make its definition visible in every translation unit where it is used without causing an ODR violation, and that makes it easier for the compiler to perform the inlining optimization. So the keyword doesn't by itself enable any new optimizations, but using it allows you to changes to how your code is structured, and those changes can enable the compiler to optimize (although a modern compiler can do optimization across translation units and then tricks like this aren't necessary either)Overthrow
You mention that inline is useful for templates, but that isn't actually true, function templates and member functions defined inside the class are automatically treated as having the inline keyword before them. It's useful for free functions that will be defined in multiple translation units (usually due to being defined in a header file and included in different TUs) and avoiding the linker errors by telling the linker to discard all but one definition while linking.Finkelstein
The inline keyword is treated as a "suggestion" to the compiler only (cplusplus.com/articles/2LywvCM9). Also, constexpr is "implicitly" inlined (en.cppreference.com/w/cpp/language/inline). There are so many other simpler/standard ways to resolve ODR issues in C++, I personally have never considered inline to resolve this. Neither of these (first two results in my Google) websites mentions ODR.Unsaddle
I
6

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.

Imperator answered 18/8, 2011 at 21:57 Comment(0)
H
-4

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: +[]{}).

Hollie answered 8/10, 2017 at 22:0 Comment(1)
inline does not imply internal linkage as you seem to be saying in your first paragraphOutlying

© 2022 - 2024 — McMap. All rights reserved.