Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “constexpr”和“const”之间的区别`_C++_C++11_Constants_Constexpr - Fatal编程技术网

C++ “constexpr”和“const”之间的区别`

C++ “constexpr”和“const”之间的区别`,c++,c++11,constants,constexpr,C++,C++11,Constants,Constexpr,constepr和const之间有什么区别 什么时候我可以只使用其中一个 我什么时候可以同时使用这两种方法?我应该如何选择一种 const适用于变量,并且防止它们在代码中被修改 constexpr告诉编译器,这个表达式会产生一个编译时常量值,因此它可以用于数组长度、赋值给const变量等地方。Oli给出的例子非常好 基本上,它们是两个不同的概念,可以(也应该)一起使用。基本含义和语法 这两个关键字都可以用于对象和函数的声明。应用于对象时的基本区别是: const将对象声明为常量。这意味着一旦

constepr
const
之间有什么区别

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

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

constexpr
告诉编译器,这个表达式会产生一个编译时常量值,因此它可以用于数组长度、赋值给
const
变量等地方。Oli给出的例子非常好

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

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

  • const
    将对象声明为常量。这意味着一旦初始化,该对象的值就不会改变,编译器可以利用这一事实进行优化。它还有助于防止程序员编写代码来修改初始化后不需要修改的对象

  • constexpr
    将对象声明为适合在标准称为常量表达式的对象中使用。但是请注意,
    constexpr
    并不是实现这一点的唯一方法

应用于函数时,基本区别在于:

  • const
    只能用于非静态成员函数,不能用于一般函数。它保证成员函数不会修改任何非静态数据成员(可变数据成员除外,可以修改)

  • constexpr
    可以与成员函数、非成员函数以及构造函数一起使用。它声明适合在常量表达式中使用的函数。编译器仅在函数满足某些标准(7.1.5/3,4)时才会接受它,最重要的是(†):

    • 函数体必须是非虚拟的并且非常简单:除了typedef和静态断言之外,只允许使用一个
      return
      语句。对于构造函数,只允许初始化列表、typedefs和静态断言。(
      =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
    
    这是可能的,因为
    N
    是常量,并且在声明时使用文本初始化,即使未声明
    constexpr
    ,也满足常量表达式的条件

那么,我实际上什么时候必须使用
constexpr

  • 类似于上面的
    N
    对象可以用作常量表达式,而无需声明
    constexpr
    。这适用于以下所有对象:
  • const
  • 整型或枚举型,以及
  • 在声明时使用本身是常量表达式的表达式初始化

[这是由于§5.19/2:常量表达式不得包含涉及“左值到右值修改,除非[…]整型或枚举型的glvalue[…]”的子表达式,这要感谢Richard Smith纠正了我先前的说法,即这适用于所有文字类型。]

  • 要使函数适合在常量表达式中使用,必须显式声明它
    constexpr
    ;仅仅满足常量表达式函数的标准是不够的。例如:

         int main()
         {
           const int N = 3;
           int numbers[N] = {1, 2, 3};  // N is constant expression
         }
    
     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
     }
    

    constexpr int N = 5;
    
    但是,请注意,在某些情况下,每个关键字都引用声明的不同部分:

    static constexpr int N = 3;
    
    int main()
    {
      constexpr const int *NP = &N;
    }
    
    这里,
    NP
    被声明为地址常量表达式,即本身是常量表达式的指针。(当通过将地址运算符应用于静态/全局常量表达式来生成地址时,这是可能的。)此处,需要
    constepr
    const
    constepr
    始终指声明的表达式(此处
    NP
    ),而
    const
    int
    (它声明一个指向常量的指针)。删除
    常量将导致表达式非法(因为(a)指向非常量对象的指针不能是常量表达式,(b)
    &N
    实际上是指向常量的指针)

    B.在成员函数声明中。在C++11中,
    constepr
    意味着
    const
    ,而在C++14和C++17中则不是这样。在C++11下声明的成员函数

    constexpr void f();
    
    需要声明为

    constexpr void f() const;
    
    < C++ > 14,以作为代码< >代码>函数> >函数> < /P> < P>根据Bjarne Stroustrup的《C++编程语言第四EDITNN》一书 •const:大致意思是“我保证不改变此值”(
    constexpr void f() const;
    
    const int dmv = 17; // dmv is a named constant
    int var = 17; // var is not a constant
    constexpr double max1 = 1.4*square(dmv); // OK if square(17) is a constant expression
    constexpr double max2 = 1.4∗square(var); // error : var is not a constant expression
    const double max3 = 1.4∗square(var); //OK, may be evaluated at run time
    double sum(const vector<double>&); // sum will not modify its argument (§2.2.5)
    vector<double> v {1.2, 3.4, 4.5}; // v is not a constant
    const double s1 = sum(v); // OK: evaluated at run time
    constexpr double s2 = sum(v); // error : sum(v) not constant expression
    
    constexpr double square(double x) { return x∗x; }
    
    const int mx = numeric_limits<int>::max();  // OK: runtime initialization
    
    int arr[mx];  // error: “constant expression required”
    
    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)
    
    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
    
    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
    
    cout << "Enter your age: ";
    int age;
    cin >> age;
    
    const int myAge{age};        // works
    constexpr int someAge{age};  // error: age can only be resolved at runtime
    
    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
    }
    
    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.
    
    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.
    
    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.
    
    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 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.
    
    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.
    
    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.
    
    #include<iostream>
    constexpr int multiply (int x, int y)
    {
    
      return x * y;
    }
    
    extern const int val = multiply(10,10);
    int main () {
      std::cout << val;
    } 
    
    val:
            .long   100  //extra external definition supplied due to extern
    
    main:
            push    rbp
            mov     rbp, rsp
            mov     esi, 100 //substituted in as an immediate
            mov     edi, OFFSET FLAT:_ZSt4cout
            call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
            mov     eax, 0
            pop     rbp
            ret
    
    __static_initialization_and_destruction_0(int, int):
            . 
            . 
            . 
    
    #include<iostream>
    const int multiply (int x, int y)
    {
    
      return x * y;
    }
    
    const int val = multiply(10,10); //constexpr is an error
    int main () {
      std::cout << val;
    }
    
    multiply(int, int):
            push    rbp
            mov     rbp, rsp
            mov     DWORD PTR [rbp-4], edi
            mov     DWORD PTR [rbp-8], esi
            mov     eax, DWORD PTR [rbp-4]
            imul    eax, DWORD PTR [rbp-8]
            pop     rbp
            ret
    
    main:
            push    rbp
            mov     rbp, rsp
            mov     eax, DWORD PTR val[rip]
            mov     esi, eax
            mov     edi, OFFSET FLAT:_ZSt4cout
            call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
            mov     eax, 0
            pop     rbp
            ret
    
    __static_initialization_and_destruction_0(int, int):
            . 
            . 
            . 
            mov     esi, 10
            mov     edi, 10
            call    multiply(int, int)
            mov     DWORD PTR val[rip], eax
    
    const int x = 10;
    int a[x] = {0};
    
    constexpr auto x = 10;
    
    struct Data {   // We can make a bit field element of struct.   
        int a:x;
     };
    
    constexpr const int* p;
    
    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};
    
    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
     };