C++ constexpr 与静态常量:更喜欢哪一个?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41125651/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:25:57  来源:igfitidea点击:

constexpr vs. static const: Which one to prefer?

c++c++11constconstexpr

提问by Mr.C64

For defining compile-time constantsof integral types like the following (at function and class scope), which syntax is best?

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

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

(1)works also for C++98/03 compilers, instead (2)requires at least C++11. Are there any other differences between the two? Should one or the other be preferred in modern C++ code, and why?

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



EDIT

编辑

I tried this sample code with Godbolt's CE:

我用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;
}

and for the static constcase this is the generated assembly by GCC 6.2:

对于这种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

On the other hand, for constexprit's:

另一方面,因为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

Although at -O3in both cases I get the same (optimized) assembly:

尽管-O3在这两种情况下我都得到了相同的(优化的)程序集:

main:
        xor     eax, eax
        ret


EDIT #2

编辑#2

I tried this simple code (live on Ideone):

我试过这个简单的代码(在 Ideone 上直播)

#include <iostream>
using namespace std;

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

which shows that const int k1is evaluated at compile-time, as it's used to calculate constexpr int k2.

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

However, there seems to be a differentbehavior for doubles. I've created a separate question for that here.

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

采纳答案by AnT

As long as we are talking about declaring compile-time constants of scalarinteger or enum types, there's absolutely no difference between using const(static constin class scope) or constexpr.

只要我们谈论声明标量整数或枚举类型的编译时常,使用const(static const在类范围内) 或constexpr.

Note that compilers are required to support static const intobjects (declared with constant initializers) in constant expressions, meaning that they have no choice but to treat such objects as compile-time constants. Additionally, as long as such objects remain odr-unused, they require no definition, which further demonstrates that they won't be used as run-time values.

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

Also, rules of constant initializationprevent local static const intobjects from being initialized dynamically, meaning that there's no performance penalty for declaring such objects locally. Moreover, immunity of integral staticobjects to ordering problems of static initialization is a very important feature of the language.

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

constexpris an extension and generalization of the concept that was originally implemented in C++ through constwith a constant initializer. For integer types constexprdoes not offer anything extra over what constalready did. constexprsimply performs an early check of the "constness" of initializer. However, one might say that constexpris a feature designed specifically for that purpose so it fits better stylistically.

constexpr是最初在 C++ 中通过const常量初始化器实现的概念的扩展和概括。对于整数类型constexpr并没有提供比const已经做过的任何额外的东西。constexpr简单地对初始化程序的“一致性”进行早期检查。但是,有人可能会说这constexpr是专门为此目的而设计的功能,因此它在风格上更适合。

回答by Guillaume Racicot

constexprvariable is guaranteed to have a value available at compile time. whereas static constmembers or constvariable could either mean a compile time value or a runtime value. Typing constexprexpress your intent of a compile time value in a much more explicit way than const.

constexpr变量保证在编译时有一个可用的值。而static const成员或const变量可能意味着编译时值或运行时值。键入constexpr以比const.

One more thing, in C++17, constexprstatic data member variables will be inline too. That means you can omit the out of line definition of static constexprvariables, but not static const.

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



As a demand in the comment section, here's a more detailed explanation about static constin function scope.

作为评论区的需求,这里有更详细的static constin function scope的解释。

A static constvariable at function scope is pretty much the same, but instead of having a automatic storage duration, it has static storage duration. That mean it's in some way the equivalent of declaring the variable as global, but only accessible in the function.

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

It is true that a staticvariable is initialize at the first call of the function, but since it's consttoo, the compiler will try to inline the value and optimize out the variable completely. So in a function, ifthe value is known at compile time for this particular variable, then the compiler will most likely optimize it out.

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

However, if the value isn't known at compile time for a static constat function scope, it might silentlymake your function (a very small bit) slower, since it has to initialize the value at runtimethe first time the function is called. Plus, it has to check if the value is initialized each time the function is called.

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

That's the advantage of a constexprvariable. If the value isn't known at compile time, it's a compilation error, not a slower function. Then if you have no way of determine the value of your variable at compile time, then the compiler will tell you about it and you can do something about it.

这就是constexpr变量的优点。如果该值在编译时未知,则是编译错误,而不是较慢的函数。然后,如果您无法在编译时确定变量的值,那么编译器会告诉您有关它的信息,您可以对此做一些事情。