constexpr和const之间有什么区别?

我什么时候只能使用其中一个?我什么时候可以同时使用这两种方法,我应该如何选择一种?


当前回答

const int var可以在运行时动态设置为一个值,一旦设置为该值,就不能再更改。

constexpr int变量不能在运行时动态设置,而是在编译时动态设置。一旦设置为该值,就不能再进行更改。

下面是一个可靠的例子:

int main(int argc, char*argv[]) {
    const int p = argc; 
    // p = 69; // cannot change p because it is a const
    // constexpr int q = argc; // cannot be, bcoz argc cannot be computed at compile time 
    constexpr int r = 2^3; // this works!
    // r = 42; // same as const too, it cannot be changed
}

上面的代码段编译得很好,我已经注释掉了导致它出错的代码段。

这里需要注意的关键概念是编译时和运行时的概念。C++中引入了新的创新,旨在尽可能在编译时**了解**某些事情,以提高运行时的性能。

任何不涉及上述两个关键概念的解释都是幻觉。

其他回答

const和constexpr都可以应用于变量和函数。尽管它们彼此相似,但实际上它们是非常不同的概念。

const和constexpr都意味着它们的值在初始化后不能更改。例如:

const int x1=10;
constexpr int x2=10;

x1=20; // ERROR. Variable 'x1' can't be changed.
x2=20; // ERROR. Variable 'x2' can't be changed.

const和constexpr之间的主要区别是它们的初始化值已知(求值)的时间。虽然const变量的值可以在编译时和运行时计算,但constexpr始终在编译时计算。例如:

int temp=rand(); // temp is generated by the the random generator at runtime.

const int x1=10; // OK - known at compile time.
const int x2=temp; // OK - known only at runtime.
constexpr int x3=10; // OK - known at compile time.
constexpr int x4=temp; // ERROR. Compiler can't figure out the value of 'temp' variable at compile time so `constexpr` can't be applied here.

了解该值在编译时或运行时是否已知的关键优势是,只要需要编译时常数,就可以使用编译时常数。例如,C++不允许您指定长度可变的C数组。

int temp=rand(); // temp is generated by the the random generator at runtime.

int array1[10]; // OK.
int array2[temp]; // ERROR.

这意味着:

const int size1=10; // OK - value known at compile time.
const int size2=temp; // OK - value known only at runtime.
constexpr int size3=10; // OK - value known at compile time.


int array3[size1]; // OK - size is known at compile time.
int array4[size2]; // ERROR - size is known only at runtime time.
int array5[size3]; // OK - size is known at compile time.

因此,常量变量可以定义编译时常量(如size1)和运行时常量(例如size2),前者可以用于指定数组大小,后者只能在运行时知道,不能用于定义数组大小。另一方面,constexpr总是定义可以指定数组大小的编译时常数。

const和constexpr也可以应用于函数。const函数必须是成员函数(方法、运算符),其中应用const关键字意味着该方法不能更改其成员(非静态)字段的值。例如

class test
{
   int x;

   void function1()
   {
      x=100; // OK.
   }

   void function2() const
   {
      x=100; // ERROR. The const methods can't change the values of object fields.
   }
};

constexpr是一个不同的概念。它将函数(成员或非成员)标记为可以在编译时求值的函数,如果编译时常量作为其参数传递。例如,你可以写这个。

constexpr int func_constexpr(int X, int Y)
{
    return(X*Y);
}

int func(int X, int Y)
{
    return(X*Y);
}

int array1[func_constexpr(10,20)]; // OK - func_constexpr() can be evaluated at compile time.
int array2[func(10,20)]; // ERROR - func() is not a constexpr function.

int array3[func_constexpr(10,rand())]; // ERROR - even though func_constexpr() is the 'constexpr' function, the expression 'constexpr(10,rand())' can't be evaluated at compile time.

顺便说一句,constexpr函数是常规C++函数,即使传递了非常量参数,也可以调用这些函数。但在这种情况下,您得到的是非常量表达式值。

int value1=func_constexpr(10,rand()); // OK. value1 is non-constexpr value that is evaluated in runtime.
constexpr int value2=func_constexpr(10,rand()); // ERROR. value2 is constexpr and the expression func_constexpr(10,rand()) can't be evaluated at compile time.

constexpr还可以应用于成员函数(方法)、运算符甚至构造函数。例如。

class test2
{
    static constexpr int function(int value)
    {
        return(value+1);
    }

    void f()
    {
        int x[function(10)];


    }
};

一个更“疯狂”的样本。

class test3
{
    public:

    int value;

    // constexpr const method - can't chanage the values of object fields and can be evaluated at compile time.
    constexpr int getvalue() const
    {
        return(value);
    }

    constexpr test3(int Value)
        : value(Value)
    {
    }
};


constexpr test3 x(100); // OK. Constructor is constexpr.

int array[x.getvalue()]; // OK. x.getvalue() is constexpr and can be evaluated at compile time.

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

constexpr告诉编译器,此表达式会产生编译时常量值,因此可以在数组长度、赋值给常量变量等位置使用。Oli给出的链接有很多很好的示例。

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

首先,两者都是c++中的限定符。声明常量的变量必须初始化,以后不能更改。因此,通常声明为常量的变量甚至在编译之前都会有一个值。

但是,对于constexpr来说,它有点不同。

对于constexpr,您可以给出一个表达式,该表达式可以在程序编译期间计算。

显然,声明为constexper的变量不能像const一样在将来更改。

const int var可以在运行时动态设置为一个值,一旦设置为该值,就不能再更改。

constexpr int变量不能在运行时动态设置,而是在编译时动态设置。一旦设置为该值,就不能再进行更改。

下面是一个可靠的例子:

int main(int argc, char*argv[]) {
    const int p = argc; 
    // p = 69; // cannot change p because it is a const
    // constexpr int q = argc; // cannot be, bcoz argc cannot be computed at compile time 
    constexpr int r = 2^3; // this works!
    // r = 42; // same as const too, it cannot be changed
}

上面的代码段编译得很好,我已经注释掉了导致它出错的代码段。

这里需要注意的关键概念是编译时和运行时的概念。C++中引入了新的创新,旨在尽可能在编译时**了解**某些事情,以提高运行时的性能。

任何不涉及上述两个关键概念的解释都是幻觉。

const和constexpr关键字概述

在C++中,如果用常量表达式初始化常量对象,我们可以在需要常量表达式的地方使用常量对象。

const int x = 10;
int a[x] = {0};

例如,我们可以在switch中使用case语句。

constexpr可以与数组一起使用。

constexpr不是类型。

constexpr关键字可以与auto关键字一起使用。

constexpr auto x = 10;

struct Data {   // We can make a bit field element of struct.   
    int a:x;
 };

如果我们用常量表达式初始化常量对象,那么该常量对象生成的表达式现在也是常量表达式。

常量表达式:可以在编译时计算其值的表达式。

x*5-4//这是一个常量表达式。对于编译器,键入此表达式和直接键入46之间没有区别。

初始化是必需的。它只能用于阅读目的。无法更改。到目前为止,“const”和“constexpr”关键字之间没有区别。

注意:我们可以在同一声明中使用constexpr和const。

constexpr const int* p;

Constexpr函数

通常,函数的返回值是在运行时获得的。但当满足某些条件时,对constexpr函数的调用将在编译时作为常量获得。

注意:在函数调用中发送给函数的参数变量的参数,如果有多个参数,则发送给所有参数变量,如果是C。E,则函数的返回值将在编译时计算!!!

constexpr int square (int a){
return a*a;
}

constexpr int a = 3;
constexpr int b = 5;

int arr[square(a*b+20)] = {0}; //This expression is equal to int arr[35] = {0};

为了使函数成为constexpr函数,函数的返回值类型和函数参数的类型必须在名为“literal type”的类型类别中。

constexpr函数是隐式内联函数。

重要一点:

无需使用常量表达式调用constexpr函数。它不是必需的。如果发生这种情况,计算将不会在编译时完成。它将被视为正常的函数调用。因此,当需要常量表达式时,我们将无法再使用此表达式。

constexpr函数所需的条件如下所示:;

1)函数参数中使用的类型和函数返回值的类型必须是文本类型。

2)函数内部不应使用具有静态寿命的局部变量。

3)如果函数是合法的,当我们在编译时使用常量表达式调用此函数时,编译器会在编译时计算函数的返回值。

4)编译器需要查看函数的代码,因此constexpr函数几乎总是在头文件中。

5)为了使我们创建的函数成为constexpr函数,函数的定义必须在头文件中。因此,无论哪个源文件包含该头文件,都将看到函数定义。

奖金

通常使用默认成员初始化,可以在类中初始化具有常量和整数类型的静态数据成员。然而,为了做到这一点,必须同时存在“常量”和“整型”。

如果我们使用静态constexpr,那么它不必是一个整型来在类中初始化它。只要用常量表达式初始化它,就没有问题。

class Myclass  {
         const static int sx = 15;         // OK
         constexpr static int sy = 15;     // OK
         const static double sd = 1.5;     // ERROR
         constexpr static double sd = 1.5; // OK
 };