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

MBZ*_*MBZ 540 c++ const constexpr c++11

constexpr和之间有什么区别const

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

jog*_*pan 539

基本含义和语法

两个关键字都可以用于对象和函数的声明.应用于对象时的基本区别是:

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

  • constexpr声明一个对象适合在标准调用常量表达式中使用.但请注意,这constexpr不是唯一的方法.

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

  • const只能用于非静态成员函数,而不能用于一般的函数.它保证成员函数不会修改任何非静态数据成员.

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

    • 函数体必须是非虚拟且非常简单的:除了typedef和static asserts之外,只return允许一个语句.对于构造函数,只允许初始化列表,typedef和static assert.(= default= delete也被允许使用,但.)
    • 由于C++ 14的规则较为宽松,是什么,因为那里面一个constexpr功能允许:asm报关,一个goto声明,带有标签以外的陈述casedefault,尝试块,非文字类型的变量的定义,定义静态或线程存储持续时间的变量,定义不执行初始化的变量.
    • 参数和返回类型必须是文字类型(即,一般来说,非常简单的类型,通常是标量或聚合)

常量表达式

如上所述,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
    
    Run Code Online (Sandbox Code Playgroud)
  • 但请注意:

    • 声明某些内容constexpr并不一定能保证在编译时对其进行评估.它可以用于此类,但它也可以在运行时评估的其他地方使用.

    • 对象可能适合在常量表达式中使用而不被声明constexpr.例:

      int main()
      {
        const int N = 3;
        int numbers[N] = {1, 2, 3};  // N is constant expression
      }
      
      Run Code Online (Sandbox Code Playgroud)

    这是可能的,因为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
    }
    
    Run Code Online (Sandbox Code Playgroud)

我什么时候可以/我应该同时使用,constconstexpr 在一起呢?

A.在对象声明中.当两个关键字都引用要声明的同一对象时,这是绝对必要的.constexpr暗示const.

constexpr const int N = 5;
Run Code Online (Sandbox Code Playgroud)

是相同的

constexpr int N = 5;
Run Code Online (Sandbox Code Playgroud)

但请注意,可能存在关键字各自引用声明的不同部分的情况:

static constexpr int N = 3;

int main()
{
  constexpr const int *NP = &N;
}
Run Code Online (Sandbox Code Playgroud)

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

B.在成员函数声明中.在C++ 11中,constexpr暗示const,而在C++ 14和C++ 17中并非如此.在C++ 11下声明的成员函数

constexpr void f();
Run Code Online (Sandbox Code Playgroud)

需要声明为

constexpr void f() const;
Run Code Online (Sandbox Code Playgroud)

在C++ 14下,为了仍然可以用作const函数.

  • @aschepler当然可以.我的主要观点是,如果你在非常量表达式上调用`constexpr`函数,例如普通变量,这是完全合法的,并且该函数将像任何其他函数一样使用.它不会在编译时进行评估(因为它不能).也许您认为这很明显 - 但如果我声明一个声明为`constexpr`的函数将始终在编译时进行求值,那么它可能会以错误的方式解释. (10认同)
  • 是的,我在谈论`constexpr`对象,而不是函数.我喜欢在对象上考虑`constexpr`以强制编译时评估值,在函数上考虑`constexpr`,以允许在编译时或运行时适当地评估函数. (5认同)
  • IMO"不一定在编译时评估"没有比将它们视为"在编译时评估"更有帮助.对常量表达式的约束意味着编译器对它进行评估相对容易.如果不满足这些约束,编译器必须抱怨.由于没有副作用,您永远无法区分编译器是否"评估"它. (3认同)
  • 这句话:_它保证成员函数不会修改任何非静态数据成员._错过了一个重要的细节.标记为`mutable`的成员也可以通过`const`成员函数进行修改. (3认同)
  • 更正:'const'仅是您不能更改变量值的限制;它不能保证价值不会改变(即被他人)。这是一个write属性,而不是read属性。 (2认同)
  • @JaredGrubb 对于 const 引用和指向 const 的指针来说,您所说的当然是正确的。我没有讨论上面的内容,因为没有 constexpr 替代品(没有对 constexpr 的引用)。也许我应该把这一点说得更清楚。但是,当涉及到实际(非引用)const 对象时,它们的值必须在初始化时定义并且不能更改。 (2认同)
  • @jogojapan见5.19/2:"左值 - 右值转换,除非它适用于[...]".Clang应该正确执行这个; 如果您发现其他情况,请提交错误. (2认同)
  • 在你的回答中:“_删除 const 会使表达式非法(因为 (a) 指向非 const 对象的指针不能是常量表达式_”似乎是错误的;标准中的上述引用仅讨论静态存储持续时间,而不涉及静态存储持续时间)对象的 `const` 性质;但是 (b) 是正确的。我还在 _C++ Primer_ 中读到,允许指向非 const 对象的 `constexpr` 指针;最后 [GCC 同意](http://coliru.stacked- crooked.com/a/e0068c9db4372f63) 也是。不过,你得到了我的 +1 :) (2认同)
  • 现在我们有了 C++14(和 C++17),我确认成员函数的 `constexpr` 不再意味着 `const`。 (2认同)
  • @Nik-Lz 当`constexpr` 函数像带有普通参数(例如局部变量)的常规函数​​函数一样使用时。 (2认同)

Kar*_*k T 114

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

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

基本上它们完全是两个不同的概念,并且可以(并且应该)一起使用.

  • const &amp; constexpr 用法,例如:http://en.cppreference.com/w/cpp/container/array/get (2认同)

zan*_*ngw 62

概观

  • const保证程序不会改变对象的值.但是,const不保证对象经历哪种类型的初始化.

    考虑:

    const int mx = numeric_limits<int>::max();  // OK: runtime initialization
    
    Run Code Online (Sandbox Code Playgroud)

    该函数max()仅返回一个文字值.但是,因为初始化程序是函数调用,所以要mx进行运行时初始化.因此,您不能将其用作常量表达式:

    int arr[mx];  // error: “constant expression required”
    
    Run Code Online (Sandbox Code Playgroud)
  • constexpr是一个新的C++ 11关键字,它让您无需创建宏和硬编码文字.在某些条件下,它还保证对象经历静态初始化.它控制表达式的评估时间.通过对其表达式执行编译时评估,constexpr您可以定义真正的常量表达式,这些表达式对于时间关键型应用程序,系统编程,模板以及一般来说依赖于编译时常量的任何代码都至关重要.

常量表达式函数

常数表达式函数是声明的函数constexpr.它的主体必须是非虚拟的,除了typedef和静态断言之外,它只包含一个return语句.它的参数和返回值必须具有文字类型.它可以与非常量表达式参数一起使用,但是当完成时,结果不是常量表达式.

常量表达式函数旨在替换硬编码文字,而不会牺牲性能或类型安全性.

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)
Run Code Online (Sandbox Code Playgroud)

常量表达式对象

常数表达式对象是声明的目的constexpr.必须使用常量表达式或由具有常量表达式参数的常量表达式构造函数构造的rvalue初始化它.

常量表达式对象的行为就像它被声明一样const,除了它在使用之前需要初始化并且它的初始化器必须是一个常量表达式.因此,常量表达式对象始终可以用作另一个常量表达式的一部分.

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
Run Code Online (Sandbox Code Playgroud)

常量表达式构造函数

常数表达式构造是声明的构造constexpr.它可以有一个成员初始化列表,但除了typedef和static asserts之外,它的主体必须是空的.它的参数必须有文字类型.

如果构造函数的参数都是常量表达式,则常量表达式构造函数允许编译器在编译时初始化对象.

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
Run Code Online (Sandbox Code Playgroud)

Scott Meyers 撰写的有效现代C++书中的提示constexpr:

  • constexpr 对象是const,并使用编译期间已知的值进行初始化;
  • constexpr 函数在使用参数调用时产生编译时结果,参数的值在编译期间是已知的;
  • constexpr对象和函数可以在比非constexpr对象和函数更广泛的上下文中使用;
  • constexpr 是对象或函数接口的一部分.

来源: 使用constexpr改进C++中的安全性,性能和封装.


Mus*_*ici 33

根据Bjarne Stroustrup的"The C++ Programming Language 4th Editon"一书
const:意思是"我保证不会改变这个值"(§7.5).这主要用于指定接口,以便可以将数据传递给函数,而不必担心它们被修改.
编译器强制执行const的承诺.
constexpr:意思是"在编译时粗略地评估"(第10.4节).这主要用于指定常量,以允许
例如:

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
Run Code Online (Sandbox Code Playgroud)

对于可在常量表达式中使用的函数,即在将由编译器计算的表达式中,必须将其定义为constexpr.
例如:

constexpr double square(double x) { return x?x; }
Run Code Online (Sandbox Code Playgroud)


要成为constexpr,函数必须相当简单:只需一个计算值的return语句.constexpr函数可以用于非常量参数,但是当完成时,结果不是常量表达式.我们允许在不需要常量表达式的上下文中使用非常量表达式参数调用constexpr函数,因此我们不能两次定义基本相同的函数:一次用于常量表达式,一次用于变量.
在少数地方,语言规则需要常量表达式(例如,数组边界(§2.2.5,§7.3),案例标签(§2.2.4,§9.4.2),一些模板参数(§25.2),以及使用constexpr声明的常量).在其他情况下,编译时评估对性能很重要.与性能问题无关,不可变性(具有不可更改状态的对象)的概念是一个重要的设计问题(第10.4节).


Tim*_*y_A 30

二者constconstexpr可以应用到变量和函数.尽管它们彼此相似,但事实上它们是非常不同的概念.

双方constconstexpr意味着它们的值不能将其初始化后更改.例如:

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.
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

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

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

int array1[10]; // OK.
int array2[temp]; // ERROR.
Run Code Online (Sandbox Code Playgroud)

所以它意味着:

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.
Run Code Online (Sandbox Code Playgroud)

这样const的变量可以定义两个编译时间常数size1,可被用来指定数组的大小和运行时间常数size2,只有在运行时是已知的,并且不能被用来定义阵列的尺寸.另一方面,constexpr总是定义可以指定数组大小的编译时常量.

双方constconstexpr可以应用到的功能了.甲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.
   }
};
Run Code Online (Sandbox Code Playgroud)

A 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.
Run Code Online (Sandbox Code Playgroud)

顺便说一下,constexpr函数是常规的C++函数,即使传递非常量参数也可以调用它们.但在这种情况下,您将获得非constexpr值.

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.
Run Code Online (Sandbox Code Playgroud)

constexpr也可以应用于成员函数(方法),运算符甚至构造函数.例如.

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

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


    }
};
Run Code Online (Sandbox Code Playgroud)

更"疯狂"的样本.

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.
Run Code Online (Sandbox Code Playgroud)


typ*_*gic 14

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

Aconstexpr int var不能在运行时动态设置,而是在编译时动态设置。一旦设置为该值,就无法再更改。

这是一个可靠的例子:

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
}
Run Code Online (Sandbox Code Playgroud)

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

这里的关键概念要注意的,是的概念compile timerun time。C++ 中引入了新的创新,旨在尽可能多地** know **在编译时提高运行时的性能。

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


Lok*_*her 8

正如@ 0x499602d2已经指出的那样,const只能确保在初始化之后无法更改值,其中constexpr(在C++ 11中引入)保证变量是编译时常量.
请考虑以下示例(来自LearnCpp.com):

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
Run Code Online (Sandbox Code Playgroud)


Lew*_*sey 7

我认为任何答案都没有真正明确它有什么副作用,或者实际上它是什么。

constexpr当使用文字或表达式初始化时,和const在名称空间/文件范围内是相同的;但对于函数来说,const可以由任何函数初始化,但constexpr由非 constexpr(未用 constexpr 或非 constexpr 表达式标记的函数)初始化将生成编译器错误。和constexpr都是const变量的隐式内部链接(实际上,如果编译 -O1 及更强的版本,它们将无法进入链接阶段,并且static不会强制编译器发出内部(本地)链接器符号 forconstconstexprat 时-O1 或更强;唯一一次这样做是在您获取变量的地址时。const并且constexpr将是一个内部符号,除非需要使用externie表示)。extern constexpr/const int i = 3;在函数上,constexpr使函数永远不会到达链接阶段(无论externinline定义中或 -O0 或 -Ofast 中),而const从不这样做,且static仅对inline-O1 及以上版本有此效果。当const/constexpr变量由函数初始化时constexpr,加载始终会使用任何优化标志进行优化,但如果函数仅是staticor inline,或者变量不是const/ ,则永远不会优化加载constexpr

标准编译(-O0)

#include<iostream>
constexpr int multiply (int x, int y)
{

  return x * y;
}

extern const int val = multiply(10,10);
int main () {
  std::cout << val;
} 
Run Code Online (Sandbox Code Playgroud)

编译为

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):
        . 
        . 
        . 
Run Code Online (Sandbox Code Playgroud)

然而

#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;
}
Run Code Online (Sandbox Code Playgroud)

编译为

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
Run Code Online (Sandbox Code Playgroud)

这清楚地表明,constexpr导致文件范围变量的初始化const/constexpr在编译时发生并且不产生全局符号,而不使用它会导致main在运行时之前发生初始化。

使用-Ofast进行编译

即使 -Ofast 也没有优化负载!https://godbolt.org/z/r-mhif,所以你需要 constexpr


constexpr也可以从其他函数内部调用函数constexpr以获得相同的结果。constexpron 函数还可以防止使用函数中编译时无法完成的任何操作;例如,对<<上的操作员进行呼叫std::cout

constexprat 块作用域的行为相同,如果由非 constexpr 函数初始化,它会产生错误;该值也会立即替换。

最后,它的主要用途就像 C 的内联函数,但只有当该函数用于初始化文件范围变量时才有效(函数在 C 上无法做到这一点,但在 C++ 上可以,因为它允许动态初始化文件)范围变量),但该函数也不能将全局/局部符号导出到链接器,即使使用extern/static,您可以inline在 C 上使用;只需使用 -O1 优化即可内联块范围变量赋值函数,而无需constexpr使用 C 和 C++。


eas*_*000 5

const 和 constexpr 关键字概述

在C++中,如果用常量表达式初始化一个const对象,那么我们就可以在任何需要常量表达式的地方使用我们的const对象。

const int x = 10;
int a[x] = {0};
Run Code Online (Sandbox Code Playgroud)

例如,我们可以在switch中做一个case语句。

constexpr 可以与数组一起使用。

constexpr 不是一种类型。

constexpr 关键字可以与 auto 关键字结合使用。

constexpr auto x = 10;

struct Data {   // We can make a bit field element of struct.   
    int a:x;
 };
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

constexpr const int* p;
Run Code Online (Sandbox Code Playgroud)

常量表达式函数

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

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

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};
Run Code Online (Sandbox Code Playgroud)

为了使函数成为 constexpr 函数,函数的返回值类型和函数参数的类型必须属于称为“文字类型”的类型类别。

constexpr 函数是隐式内联函数。

重要的一点:

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

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

1)函数参数使用的类型和函数返回值的类型必须是字面量类型。

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

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

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

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

奖金

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

如果我们使用 static 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
 };
Run Code Online (Sandbox Code Playgroud)

  • *“如果使用常量表达式初始化 const 对象,则我们可以在需要常量表达式的任何地方使用 const 对象。”* 仅适用于整型常量。 (2认同)