`constexpr`和`const`之间的区别?
发布日期:2021-05-07 00:50:44 浏览次数:18 分类:技术文章

本文共 2274 字,大约阅读时间需要 7 分钟。

基本含义和语法

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

  • const声明一个对象为常量。这意味着一个保证,一旦初始化,该对象的值不会改变,编译器可以利用这个事实进行优化。它还有助于防止程序员编写修改初始化后不打算修改的对象的代码。
  • constexpr声明一个对象适合在Standard调用常量表达式中使用。但请注意,这constexpr不是唯一的方法。

应用于功能的基本区别是:

  • const只能用于非静态成员函数,而不能用于一般函数。它保证了成员函数不会修改任何非静态数据成员。
  • constexpr可以与成员和非成员函数以及构造函数一起使用。它声明了适用于常量表达式的函数。如果函数符合某些标准(7.1.5 / 3,4),编译器将只接受它,最重要的是(†):
    • 函数体必须是非虚拟的,非常简单:除typedef和静态断言之外,只return允许一个语句。在构造函数的情况下,只允许初始化列表typedefs和静态声明。(= default= delete也被允许使用,但。)
    • 参数和返回类型必须是文字类型(即一般来说,非常简单的类型,通常是标量或集合)

     

常量表达式

如上所述,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 return 0; }

    这是可能的,因为N在声明时使用常量来保持常量和初始化,即使没有声明,它也满足常量表达式的条件constexpr

那么我什么时候需要使用constexpr

  • 像上面这样的对象N可以作为常量表达式使用而不需要声明constexpr。所有对象都是如此:
    • const
    • 积分或枚举类型
    • 在声明时用一个本身就是常量表达式的表达式进行初始化

    [这是由于§5.19/ 2:一个常量表达式不能包括一个子表达式,涉及“左值,右值修改,除非[...]整数或枚举类型的glvalue”感谢理查史密斯纠正我早些时候声称这对所有字面类型都是正确的。]

  • 要使函数适合在常量表达式中使用,必须明确声明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 return 0; }

我什么时候可以同时使用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;  return 0;}

在这里,NP被声明为一个地址常量表达式,即一个本身就是一个常量表达式的指针。(当通过将地址运算符静态/全局常量表达式生成的地址。这是可能的。)在这里,无论是constexprconst是必需的:constexpr总是指表达被宣布(在这里NP),而const指的是int(它声明了一个指针-给const)。删除const会导致表达式不合法(因为(a)非const对象的指针不能是常量表达式,(b)&N实际上是指向常量的指针)。

B.在成员函数声明中。在C ++ 11中,也constexpr暗示const了成员函数。但是,这在C ++ 14中可能会改变。根据目前的草案,由于建议修改§7.1.5/ 8 ,constexprconst 仅针对对象,而不针对成员职能。因此,在C ++ 11下声明一个成员函数为

constexpr void f();

将不得不被宣布为

constexpr void f() const;

在C ++ 14下仍然可以用作const函数。最好将你的constexpr成员函数标记为const现在,以免稍后改变很多代码。

上一篇:【浅谈】main函数的三个参数
下一篇:C++ 11 新特性: constexpr变量和constexpr函数

发表评论

最新留言

关注你微信了!
[***.104.42.241]2025年04月04日 19时24分49秒