首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >`constexpr`和`const`之间的区别?

`constexpr`和`const`之间的区别?
EN

Stack Overflow用户
提问于 2018-01-27 06:52:46
回答 5查看 0关注 0票数 0

constexpr和之间有什么区别const

  • 我什么时候可以只使用其中一个?
  • 我什么时候可以使用,我应该如何选择?
EN

回答 5

Stack Overflow用户

发布于 2018-01-27 12:51:33

基本含义和语法

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

  • 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

代码语言:javascript
复制
constexpr const int N = 5;

是相同的

代码语言:javascript
复制
constexpr int N = 5;

但是,请注意,可能会出现以下情况:关键字分别指向声明的不同部分:

代码语言:javascript
复制
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下声明一个成员函数为

代码语言:javascript
复制
constexpr void f();

将不得不被宣布为

代码语言:javascript
复制
constexpr void f() const;

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

票数 0
EN

Stack Overflow用户

发布于 2018-01-27 13:22:04

const适用于变量,并防止它们在代码中被修改

constexpr告诉编译器,这个表达式产生一个编译时间的常量值,所以它可以用在像数组长度,赋值给const变量等等的地方.Oli给出的链接有很多很好的例子。

基本上他们是两个不同的概念,可以(也应该)一起使用。

票数 0
EN

Stack Overflow用户

发布于 2018-01-27 14:26:29

概述

  • const保证一个程序不改变对象的值然而,const不能保证对象经历哪种类型的初始化。 考虑: const int mx = numeric_limits<int>::max(); // OK:

运行时初始化 max()只返回一个文字值。但是,由于初始化程序是函 数调用,mx运行时初始化。因此,不能将其用作常数表达 式* int arr[mx]; // error: “constant expression required”

  • constexpr是一个新的C++11关键字,它使你不必创建宏和硬编码文字。它还保证,在某些条件下,物体静态初始化它控制表达式的计算时间。通过强制表达式的编译时计算,,,constexpr让您定义为true常数表达式对于任何依赖编译时常量的代码来说,这对于时间关键的应用程序、系统编程、模板以及一般情况下都是至关重要的。

常数表达式函数

一个常数表达式函数是否声明了一个函数?constexpr它的主体必须是非虚拟的,并且只包含一个返回语句,除了类型和静态断言。其参数和返回值必须具有文字类型。它可以与非常量表达式参数一起使用,但当这样做时,结果不是常量表达式。

常量表达式函数用于替换硬编码文字在不牺牲性能或类型安全的情况下。

代码语言:javascript
复制
constexpr int max() { return INT_MAX; }           // OK
constexpr long long_max() { return 2147483647; }  // OK
constexpr bool get_val()
{
    bool res = false;
    return res;
}  // error: body is not just a return statement

constexpr int square(int x)
{ return x * x; }  // OK: compile-time evaluation only if x is a constant expression
const int res = square(5);  // OK: compile-time evaluation of square(5)
int y = getval();
int n = square(y);          // OK: runtime evaluation of square(y)

常数表达式对象

常数表达式对象是声明的对象吗?constexpr它必须用一个常量表达式或由带有常量表达式参数的常数表达式构造函数构造的rvalue来初始化。

常量表达式对象的行为就像声明了它一样。const,除非它需要在使用前进行初始化,而且它的初始化程序必须是一个常量表达式。因此,常数表达式对象总是可以作为另一个常量表达式的一部分使用.

代码语言:javascript
复制
struct S
{
    constexpr int two();      // constant-expression function
private:
    static constexpr int sz;  // constant-expression object
};
constexpr int S::sz = 256;
enum DataPacket
{
    Small = S::two(),  // error: S::two() called before it was defined
    Big = 1024
};
constexpr int S::two() { return sz*2; }
constexpr S s;
int arr[s.two()];  // OK: s.two() called after its definition

常式构造函数

常式构造函数是否声明了构造函数?constexpr它可以有一个成员初始化列表,但是它的主体必须是空的,除了类型防御和静态断言。其参数必须具有文字类型。

常数表达式构造函数允许编译器在编译时初始化对象,条件是构造函数的参数都是常量表达式。

代码语言:javascript
复制
struct complex
{
    // constant-expression constructor
    constexpr complex(double r, double i) : re(r), im(i) { }  // OK: empty body
    // constant-expression functions
    constexpr double real() { return re; }
    constexpr double imag() { return im; }
private:
    double re;
    double im;
};
constexpr complex COMP(0.0, 1.0);         // creates a literal complex
double x = 1.0;
constexpr complex cx1(x, 0);              // error: x is not a constant expression
const complex cx2(x, 1);                  // OK: runtime initialization
constexpr double xx = COMP.real();        // OK: compile-time initialization
constexpr double imaglval = COMP.imag();  // OK: compile-time initialization
complex cx3(2, 4.6);                      // OK: runtime initialization
  • constexpr对象是Const,并使用编译期间已知的值初始化;
  • constexpr函数在调用参数时产生编译时的结果,这些参数的值在编译期间是已知的;
  • constexpr对象和函数可用于比非-constexpr对象和功能;
  • constexpr是对象或函数接口的一部分。

资料来源:用COMPEER改进C++的安全性、性能和封装...

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100007250

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档