C++ constexpr和静态constexpr全局变量之间的差异

C++ constexpr和静态constexpr全局变量之间的差异,c++,c++11,constexpr,linkage,C++,C++11,Constexpr,Linkage,在C++11标准中,当在标题中定义时,constexpr和static constexpr全局变量之间有什么区别?更具体地说,当多个翻译单元包含相同的标题时,哪个声明(如果有)可以保证跨翻译单元定义相同的变量 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、 cp

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

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"

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

在C++14中,不能将变量声明为
constexpr
,并使其具有外部链接,除非只在一个翻译单元中执行此操作。原因是
constexpr
变量需要一个初始值设定项,而带有初始值设定项的声明是一个定义,并且只能有一个定义

但是,您可以使用一个普通的整数常量,您可以将它声明(不定义)为
extern
,在定义它的转换单元中,它甚至可以用作常量表达式:

lib.h:

extern const int a;
#include "lib.h"

const int a = 10;

int b[a] = {1, 2, 3};   // OK in this translation unit
lib.cpp:

extern const int a;
#include "lib.h"

const int a = 10;

int b[a] = {1, 2, 3};   // OK in this translation unit
在C++17中,有一个新特性“内联变量”,它允许您说:

inline constexpr int a = 10;

这是一个可以重复出现的“内联定义”,每个定义定义相同的实体(就像语言中的所有其他“内联”实体一样)。

我认为本文的解释更清楚

由于const globals具有内部链接,因此每个.cpp文件都会获得链接器看不到的全局变量的独立版本。在大多数情况下,由于这些是常量,编译器只需优化变量即可。
术语“优化离开”指的是编译器通过以不影响程序输出的方式删除内容来优化程序性能的任何过程。例如,假设您有一个常量变量x,它被初始化为值4。只要代码引用变量x,编译器就可以将x替换为4(因为x是常量,我们知道它永远不会更改为不同的值),并且避免创建和初始化一个变量

因此,“cint”和“scint”都是内部链接变量

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

inline constexpr double pi = 0;
工作机制:

C++17引入了一个称为内联变量的新概念。在C++中,内联术语已经演变为“允许多个定义”。因此,内联变量是允许在多个文件中定义而不违反一个定义规则的变量。默认情况下,内联全局变量具有外部链接

内联变量有两个必须遵守的主要限制: 1) 内联变量的所有定义必须相同(否则,将导致未定义的行为)。 2) 内联变量定义(不是正向声明)必须存在于使用该变量的任何文件中

编译器将把所有内联定义合并为单个变量定义。这允许我们在头文件中定义变量,并将它们视为.cpp文件中某个地方只有一个定义。这些变量在包含它们的所有文件中也保留其常量


没有区别<代码>常量表达式意味着
常量
const
暗示
static
。无:
constexpr
变量暗示
const
,默认情况下,命名空间范围内的const整型变量具有内部链接。@CPPNearner:Nit:我不太愿意说“const暗示static”,因为
extern const int
是有效的,但是
extern static const int
不是——因此
static
没有“隐含”那么多,因为它是某种类型的“默认值”。@KerrekSB为了确保我理解,无论
constepr
还是
static constepr
都不允许我跨不同的翻译单元获取相同的对象?@Danra:C++14中,没有,您必须改用
extern const int
(它仍然适合作为定义它的TU中的常量表达式,因为您需要一个初始值设定项作为常量表达式使用)。在C++17中,您将使用
内联constexpr int a=10
获取单个对象。在C++17之前,头文件中可能有一个
constexpr
定义,但您必须使用各种解决方法,例如在
内联constexpr
函数中有一个
constexpr static
变量。@DanielH:是的,可能,我的意思是,在头文件中,
inline constepr int I(){static constexpr int value=17;return value;}
应该可以工作,然后你可以说
I()
。使用函数调用语法很奇怪,但我认为它是有效的。@DanielH:不,对不起,你说得对,那个很好。我弄糊涂了。一个不好的例子是
static constexpr int a=10;inline constexpr const int&f(){return a;}
@KerrekSB是的,您需要
static
变量位于函数内部。同样不好的是,大多数试图摆脱函数调用语法的尝试,如
inline constexpr const Foo&f(){static constexpr Foo x;return x;}constexpr Foo&x=f()。我想如果你能让它成为一个类成员,你就可以做到,尽管我不记得怎么做了,它涉及到一些复杂的重定向。