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

时间:2016-12-13 16:14:26

标签: c++ c++11 const constexpr

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

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

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

修改

我使用Godbolt's 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

我尝试了这个简单的代码(live on 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创建了一个单独的问题。

2 个答案:

答案 0 :(得分:31)

保证

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

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

作为评论部分的要求,这里有关于函数范围static const的更详细说明。

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

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

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

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

答案 1 :(得分:17)

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

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

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

constexpr是概念的扩展和概括,最初是在C ++中通过const使用常量初始化程序实现的。对于整数类型,constexpr不会提供const以外的任何额外内容。 constexpr只是对&#34; constness&#34;进行早期检查。初始化程序。但是,有人可能会说constexpr是专为此目的而设计的功能,因此它更符合风格。