constexpr 和 static constexpr 全局变量的区别

Difference between constexpr and static constexpr global variable

在 C++11 标准中,constexprstatic constexpr 全局变量定义在 header 中有什么区别?更具体地说,当多个翻译单元包含相同的 header 时,哪个声明(如果有)保证在翻译单元中定义相同的变量?

例如

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"

在您当前的示例中没有区别:在变量声明中,constexpr 意味着 const,并且命名空间范围内的 const 变量默认具有内部链接(因此添加 static不会改变任何东西)。

在 C++14 中,您不能将变量声明为 constexpr 并使其具有外部链接,除非您只在一个翻译单元中这样做。原因是constexpr变量需要初始化器,有初始化器的声明就是一个定义,你必须只有一个定义。

但是,您可以做的是使用一个普通的整数常量,您可以将其声明(而不是定义)为extern,并在它所在的翻译单元中被定义它甚至可以用作常量表达式:

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

在 C++17 中,有一个新特性 "inline variables" 让你说:

inline constexpr int a = 10;

这是一个可以重复出现的"inline definition",每个定义都定义了相同的实体(就像语言)。

我觉得这篇文章解释的比较清楚。 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.

所以,"cint "和"scint"都是内部链接变量。

C++ 17之后定义全局变量的最佳实践:

inline constexpr double pi = 0;

工作机制:

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.

如果可以,最好使用 static constexpr,因为使用 constexpr 它取决于工具链在 compile-time 上完成的可能性。 Gcc 最激进,MSVS 最不激进,clang 介于两者之间。

与其将某些值留给优化器来决定,不如在 compile-time 时更明确并强制执行。

参考:

https://www.youtube.com/watch?v=4pKtPWcl1Go