constexpr与静态const:哪一个更喜欢?

Mr.*_*C64 40 c++ const constexpr c++11

定义整数类型的编译时常量,如下所示(在函数和类范围内),哪种语法最好?

static const int kMagic = 64; // (1)
constexpr int kMagic = 64;    // (2)
Run Code Online (Sandbox Code Playgroud)

(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;
}
Run Code Online (Sandbox Code Playgroud)

对于这种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
Run Code Online (Sandbox Code Playgroud)

另一方面,因为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
Run Code Online (Sandbox Code Playgroud)

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

main:
        xor     eax, eax
        ret
Run Code Online (Sandbox Code Playgroud)

编辑#2

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

#include <iostream>
using namespace std;

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

这表明它const int k1是在编译时评估的,因为它用于计算constexpr int k2.

但是,s 似乎有不同的行为double.我在这里为此创建了一个单独的问题.

Gui*_*cot 34

constexpr保证变量在编译时具有可用值.而static const成员或const变量可以表示编译时值或运行时值.键入constexpr以比语言更明确的方式表达编译时间值的意图const.

还有一件事,在C++ 17中,constexpr静态数据成员变量也是内联的.这意味着您可以省略static constexpr变量的外联定义,但不能static const.


作为评论部分的要求,这里有一个关于static const功能范围的更详细的解释.

static const功能范围内的变量几乎相同,但它具有静态存储持续时间,而不是具有自动存储持续时间.这意味着它在某种程度上相当于将变量声明为全局变量,但只能在函数中访问.

确实,static变量在函数的第一次调用时初始化,但由于它也是const如此,编译器将尝试内联值并完全优化变量.所以在函数中,如果在编译时知道该特定变量的值,那么编译器很可能会优化它.

但是,如果在编译时未知static const函数作用域的值,它可能会静默地使您的函数(非常小的一点)变慢,因为它必须在第一次调用函数时在运行时初始化该值.另外,每次调用函数时都必须检查值是否已初始化.

这是constexpr变量的优势.如果在编译时未知该值,则表示编译错误,而不是较慢的函数.然后,如果你无法在编译时确定变量的值,那么编译器会告诉你它,你可以对它做些什么.

  • 加上"稍微慢一点"的部分:不仅因为它必须在第一次调用函数时初始化值,而且还必须在每次调用的运行时确定*是否*这是第一次调用它.这不是微不足道的,请参阅https://godbolt.org/g/wBejUj (5认同)
  • @ Mr.C64:关键字`static`与编译时*const-ness*或*computability*没有任何关系.在命名空间级别,它会影响链接; 在类范围内,它使所有实例的成员*common*; 在函数范围内,它使变量在调用之间*持久*. (2认同)

AnT*_*AnT 18

只要我们讨论声明标量整数或枚举类型的编译时常,在使用const(static const在类范围内)或constexpr.之间绝对没有区别.

请注意,编译器需要static const int在常量表达式中支持对象(使用常量初始化器声明),这意味着他们别无选择,只能将这些对象视为编译时常量.此外,只要这些对象保持未使用状态,它们就不需要定义,这进一步证明它们不会用作运行时值.

此外,常量初始化规则会阻止本地static const int对象动态初始化,这意味着在本地声明此类对象不会有性能损失.此外,整体static对象对静态初始化的排序问题的免疫性是该语言的一个非常重要的特征.

constexpr是一个概念的扩展和概括,最初是在C++中通过const常量初始化器实现的.对于整数类型constexpr,不提供任何额外的功能const.constexpr只需对初始化程序的"常量"进行早期检查.但是,有人可能会说这constexpr是专门为此目的而设计的功能,因此它更符合风格.

  • 感谢您的回答。顺便说一句,似乎](http://stackoverflow.com/q/41141734/1629821)在用“const”初始化“constexpr”时,“double”的处理方式与“int”不同(但在MSVC中除外)。 (2认同)