Reputation: 9926
In the C++11 standard, what is the difference between constexpr
and static constexpr
global variables when defined in a header? More specifically, when multiple translation units include the same header, which declaration (if any) is guaranteed to define the same variable across the translation units?
e.g.,
cexpr.h:
#ifndef CEXPR_H
#define CEXPR_H
constexpr int cint = 1;
static constexpr int scint = 1;
#endif
a.cpp:
#include "cexpr.h"
b.cpp:
#include "cexpr.h"
Upvotes: 42
Views: 34559
Reputation: 1781
If you can, prefer the static constexpr
because with the constexpr
it depends on the toolchain how likely it will get done on compile-time. Gcc is most aggressive, MSVS least aggressive and clang is in between.
Instead of leaving some values up to optimizer to decide it will do it at compile-time be more explicit and force it.
Reference:
https://www.youtube.com/watch?v=4pKtPWcl1Go
Upvotes: 4
Reputation: 121
I think this article explains more clear. 6.8 — Global constants and inline variables
Because const globals have internal linkage, each .cpp file gets an independent version of the global variable that the linker can’t see. In most cases, because these are const, the compiler will simply optimize the variables away.
The term “optimizing away” refers to any process where the compiler optimizes the performance of your program by removing things in a way that doesn’t affect the output of your program. For example, lets say you have some const variable x that’s initialized to value 4. Wherever your code references variable x, the compiler can just replace x with 4 (since x is const, we know it won’t ever change to a different value) and avoid having to create and initialize a variable altogether.
So, the "cint " and "scint" are all internal linkage variables.
The best practice to define global variable after C++ 17:
inline constexpr double pi = 0;
Working Mechanism:
C++17 introduced a new concept called inline variables. In C++, the term inline has evolved to mean “multiple definitions are allowed”. Thus, an inline variable is one that is allowed to be defined in multiple files without violating the one definition rule. Inline global variables have external linkage by default.
Inline variables have two primary restrictions that must be obeyed: 1) All definitions of the inline variable must be identical (otherwise, undefined behavior will result). 2) The inline variable definition (not a forward declaration) must be present in any file that uses the variable.
The compiler will consolidate all inline definitions into a single variable definition. This allows us to define variables in a header file and have them treated as if there was only one definition in a .cpp file somewhere. These variables also retain their constexpr-ness in all files in which they are included.
Upvotes: 6
Reputation: 477494
In your current example there is no difference: On variable declarations, constexpr
implies const
, and a const variable at namespace scope has internal linkage by default (so adding static
does not change anything).
In C++14, you cannot declare a variable as constexpr
and have it have external linkage unless you only ever do this in one single translation unit. The reason is that constexpr
variables require an initializer, and a declaration with initializer is a definition, and you must only have a single definition.
However, what you can do is use a normal integral constant, which you can declare (not define) as extern
, and in the translation unit where it is defined it can even be used as a constant expression:
lib.h:
extern const int a;
lib.cpp:
#include "lib.h"
const int a = 10;
int b[a] = {1, 2, 3}; // OK in this translation unit
In C++17, there is a new feature "inline variables" which lets you say:
inline constexpr int a = 10;
And this is an "inline definition" that can appear repeatedly, and each definition defines the same entity (just like all the other "inline" entities in the language).
Upvotes: 38