c++ - `constexpr` 和 `const` 的区别

标签 c++ c++11 constants constexpr

constexpr有什么区别和 const ?

  • 我什么时候可以只使用其中之一?
  • 我什么时候可以同时使用,我应该如何选择一个?
  • 最佳答案

    基本含义和语法
    这两个关键字都可以在对象和函数的声明中使用。应用于对象时的基本区别是:

  • const将对象声明为常量。这意味着保证一旦初始化,该对象的值就不会改变,并且编译器可以利用这一事实进行优化。它还有助于防止程序员编写修改初始化后不打算修改的对象的代码。
  • constexpr声明一个对象适用于标准所谓的常量表达式。但请注意 constexpr不是唯一的方法来做到这一点。

  • 当应用于函数时,基本的区别是:
  • const只能用于非静态成员函数,不能用于一般函数。它保证成员函数不会修改任何非静态数据成员(可变数据成员除外,无论如何都可以修改)。
  • constexpr可以与成员和非成员函数以及构造函数一起使用。它声明了适合在常量表达式中使用的函数。编译器只会在函数满足特定条件 (7.1.5/3,4) 时才会接受它,最重要的是 (†):
  • 函数体必须是非虚拟的并且非常简单:除了 typedef 和静态断言,只有一个 return声明是允许的。对于构造函数,只允许使用初始化列表、typedef 和静态断言。 (不过,= default= delete 也是允许的。)
  • 从 C++14 开始,规则更加宽松,从那时起在 constexpr 函数中允许使用:asm声明,goto声明,带有除 case 之外的标签的声明和 default ,try-block,非文字类型变量的定义,静态或线程存储期的变量的定义,不执行初始化的变量的定义。
  • 参数和返回类型必须是文字类型(即,一般来说,非常简单的类型,通常是标量或聚合)


  • 常量表达式
    如上所述,constexpr声明适合在常量表达式中使用的对象和函数。常量表达式不仅仅是常量:
  • 它可以用在需要编译时评估的地方,例如模板参数和数组大小说明符:
      template<int N>
      class fixed_size_list
      { /*...*/ };
    
      fixed_size_list<X> mylist;  // X must be an integer constant expression
    
      int numbers[X];  // X must be an integer constant expression
    
  • 但请注意:
  • 声明为 constexpr不一定保证它会在编译时被评估。它可以用于此类,但它也可以用于在运行时进行评估的其他地方。
  • 对象可能适合在常量表达式中使用而无需声明 constexpr .例子:
         int main()
         {
           const int N = 3;
           int numbers[N] = {1, 2, 3};  // N is constant expression
         }
    
    这是可能的,因为 N , 是常量并在声明时用文字初始化,满足常量表达式的标准,即使它没有声明 constexpr .

  • 那么我实际上什么时候必须使用 constexpr ?
  • 对象 喜欢 N以上可以用作常量表达式而无需声明constexpr .这适用于所有对象:
  • const
  • 整数或枚举类型和
  • 在声明时用本身是常量表达式的表达式初始化

  • [这是由于 §5.19/2:常量表达式不得包含涉及“左值到右值修改的子表达式,除非 [...] 整数或枚举类型的泛左值 [...]” 感谢 Richard Smith 更正我的早先声称这适用于所有文字类型。]
  • 对于 功能为了适合在常量表达式中使用,它 必须明确声明 constexpr ;仅仅满足常量表达式函数的标准是不够的。例子:
     template<int N>
     class list
     { };
    
     constexpr int sqr1(int arg)
     { return arg * arg; }
    
     int sqr2(int arg)
     { return arg * arg; }
    
     int main()
     {
       const int X = 2;
       list<sqr1(X)> mylist1;  // OK: sqr1 is constexpr
       list<sqr2(X)> mylist2;  // wrong: sqr2 is not constexpr
     }
    

  • 我什么时候可以/应该同时使用两者,constconstexpr一起?
    A. 在对象声明中。 当两个关键字都指向要声明的同一个对象时,这是不必要的。 constexpr暗示 const .
    constexpr const int N = 5;
    
    是相同的
    constexpr int N = 5;
    
    但是,请注意,可能存在每个关键字都指代声明的不同部分的情况:
    static constexpr int N = 3;
    
    int main()
    {
      constexpr const int *NP = &N;
    }
    
    在这里,NP被声明为一个地址常量表达式,即一个本身就是一个常量表达式的指针。 (当通过将地址运算符应用于静态/全局常量表达式来生成地址时,这是可能的。)这里,constexprconst需要:constexpr总是指被声明的表达式(这里是 NP ),而 constint (它声明了一个指向常量的指针)。删除 const会使表达式非法(因为 (a) 指向非常量对象的指针不能是常量表达式,并且 (b) &N 实际上是指向常量的指针)。
    B. 在成员函数声明中。 在 C++11 中,constexpr暗示 const ,而在 C++14 和 C++17 中则不然。在 C++11 下声明为的成员函数
    constexpr void f();
    
    需要声明为
    constexpr void f() const;
    
    在 C++14 下,为了仍可用作 const功能。

    关于c++ - `constexpr` 和 `const` 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14116003/

    相关文章:

    c++ - 是否可以在 C++ 类中声明一个虚拟静态常量值?

    可以从编译时未知的其他地方修改 const 变量吗

    c++ - 为什么我不能用一个未命名的临时对象构造一个 std::istream_iterator?

    c++ - 如何在运行时检测默认 GPU?

    C# DeflateStream 使用 C++ 解压缩

    c++ - 向后可变参数模板

    c++ - 一个简单的 pthread_create 在 Qt 中导致 100% 的 CPU 使用率

    c++ - 一些 std::unique_ptr 使用和 "gotchas"

    c++ - 如何在不导致复制的情况下将 char 数据附加到 std::vector

    c++ - 如何在 C++ 中解释 "const int *const & variable"