constexpr 与 static const:更喜欢哪一个? [已关闭]

问题描述 投票:0回答:2

对于像下面这样的整型类型定义编译时常量(在函数和类范围内),哪种语法最好?

static const int kMagic = 64; // (1)
constexpr int kMagic = 64;    // (2)

(1)
也适用于 C++98/03 编译器,而
(2)
至少需要 C++11。两者之间还有其他区别吗?现代 C++ 代码中应该首选其中之一吗?为什么?


编辑

我用 Godbolt 的 CE 尝试了这个示例代码:

int main()
{
#define USE_STATIC_CONST
#ifdef USE_STATIC_CONST
  static const int kOk = 0;
  static const int kError = 1;
#else
  constexpr int kOk = 0;
  constexpr int kError = 1;
#endif
  return kOk;
}

对于

static const
情况,这是 GCC 6.2 生成的程序集:

main::kOk:
        .zero   4
main::kError:
        .long   1
main:
        push    rbp
        mov     rbp, rsp
        mov     eax, 0
        pop     rbp
        ret

另一方面,对于

constexpr
来说:

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 0
        mov     DWORD PTR [rbp-8], 1
        mov     eax, 0
        pop     rbp
        ret

虽然在

-O3
在这两种情况下我都得到相同的(优化的)组件:

main:
        xor     eax, eax
        ret

编辑#2

我尝试了这个简单的代码(在 Ideone 上运行)

#include <iostream>
using namespace std;

int main() {
    const int k1 = 10;
    constexpr int k2 = 2*k1;
    cout << k2 << '\n';
    return 0;
}

这表明

const int k1
编译时进行评估,因为它用于计算
constexpr int k2

但是,double 似乎有一种“不同”的行为。我为此创建了一个单独的问题

here

c++ c++11 constants constexpr
2个回答
78
投票
constexpr

变量保证在

编译时
有一个可用的值,而static const成员或
const
变量可以表示编译时值或运行时值。
constexpr
以比
const
更明确的方式表达编译时值的意图。
还有一件事:在 C++17 中,

constexpr

静态数据成员变量也将是

内联
。这意味着您可以省略 static constexpr 变量的异常定义,但不能省略
static const

作为评论区的需求,这里对函数作用域中的
static const

进行更详细的解释。

函数作用域中的 
static const

变量几乎相同,但它没有自动存储持续时间,而是具有

static

 存储持续时间。这意味着它在某种程度上相当于将变量声明为全局变量,但只能在函数中访问。
确实,static

变量在函数的第一次调用时被初始化,但由于它也是

const

,编译器将尝试内联该值并完全优化该变量。因此,在函数中,
if
在编译时已知该特定变量的值,那么编译器很可能会对其进行优化。
但是,如果在编译时在函数作用域中未知static const

的值,则可能会

默默地

使您的函数(非常小一点)变慢,因为它必须在
运行时初始化该值第一次调用该函数。另外,它必须在每次调用函数时检查该值是否已初始化。 这就是 constexpr

变量的优点。如果在编译时未知该值,则这是一个“编译错误”,而不是一个较慢的函数。然后,如果您无法在编译时确定变量的值,那么编译器会告诉您这一点,您可以采取一些措施。


只要我们讨论声明 scalar

整数或枚举类型的编译时常量,使用

45
投票
(类作用域中的

static const)或 constexpr

 之间绝对没有区别。 
请注意,编译器需要支持常量表达式中的
static const int
对象(用常量初始值设定项声明),这意味着它们别无选择,只能将此类对象视为编译时常量。此外,只要此类对象保持 odr-unused,它们就不需要定义,这进一步表明它们不会被用作运行时值。

此外,

常量初始化

的规则可以防止本地
static const int

对象被动态初始化,这意味着在本地声明此类对象不会造成性能损失。此外,积分

static 对象对静态初始化的排序问题的免疫力是该语言的一个非常重要的特性。

constexpr
 是最初通过带有常量初始值设定项的 
const

在 C++ 中实现的概念的扩展和概括。对于整数类型,

constexpr

 不提供任何超出 
const
 已经提供的功能。 
constexpr
 只是对初始化器的“常量性”进行早期检查。然而,有人可能会说 
constexpr
 是专门为此目的而设计的功能,因此它更适合风格。
© www.soinside.com 2019 - 2024. All rights reserved.