Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Killing Magic Numbers: "const int" vs "constexpr int" (or is there no difference in the end)

Let's say I have a magic number I want to get rid off...

//whatever.cpp

for (int i = 0; i < 42; i++)
{
    //...
}

Reasonably I could kill it in two ways:

Either with const int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
or with constexpr int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
in the source .cpp file.

Is there any meaningful difference between the two in this case (I recall the compiler deducing that - in either case - that the value does not change and thus the 42 is actually hardcoded in the resulting loop/unrolled loop/whatever machine-code) or does it come down to personal taste?

In a related issue: what if the magic number (and thus the thing that replaces it) were declared in a header (.h) file instead of a source (.ccp) file - would that change things (and if so, how)?

like image 608
CharonX Avatar asked Jul 09 '19 10:07

CharonX


People also ask

What is the difference between constexpr and const?

The primary difference between const and constexpr variables is that the initialization of a const variable can be deferred until run time. A constexpr variable must be initialized at compile time. All constexpr variables are const .

Why is constexpr over const?

Overview. const guarantees that a program does not change an object's value. However, const does not guarantee which type of initialization the object undergoes. constexpr is a new C++11 keyword that rids you of the need to create macros and hardcoded literals.


2 Answers

const int can be used as part of a constant expression only if it was initialized from one, but it doesn't give you the guarantee that it was.

const int i = 42; // OK, usable in a constant expression
int j = 42;
const int k = j;  // OK, not usable in a constant expression

constexpr int guarantees that the initializer for your variable is a constant expression, otherwise your program will not compile.

constexpr int i = 42; // OK, usable in a constant expression
int j = 42;
constexpr int k = j;  // Compile-time error, 'j' is not a constant expression

Therefore, if you want to ensure that your initializer is indeed a constant expression, constexpr is a better choice.

like image 139
Vittorio Romeo Avatar answered Oct 09 '22 01:10

Vittorio Romeo


Is there any meaningful difference between the two in this case (I recall the compilering deducing that - in either case - the value does not change and actually hardcodes the 42 in the resulting loop/unrolled loop/whatever code) or does it come down to personal taste?

There won't be any difference in codegen in the case you have shown.

However, the difference is that a constexpr variable guarantees that the value is known at compile-time. See VittorioRomeo's answer.

It is also good to write constexpr if it is truly a compile-time value, for documentation purposes: when someone reads your code and sees constexpr, they automatically know it is a truly fixed value. This is important in the case the initialization is non-trivial (e.g. a call to a function).

You can also see constexpr variables as the true replacement for C macros that contained literals (e.g. #define FOO 123).

Finally, remember that constexpr implies const.

In a related issue: what if the magic number (and the thing that replaces it) were declared in a header file instead of a .ccp file - would that change things?

No. However, if you are declaring global variables in a header file, you probably want to use inline (available in C++17) on top of constexpr, so that you only have a single entity in the program, which is an advantage to avoid ODR issues and possibly save memory and initialization time.

See Should `const` and `constexpr` variables in headers be `inline` to prevent ODR violations? for more information.

like image 45
Acorn Avatar answered Oct 09 '22 01:10

Acorn