Difference between `constexpr` and `const`

后端 未结 9 1604
无人共我
无人共我 2020-11-22 03:48

What\'s the difference between constexpr and const?

  • When can I use only one of them?
  • When can I use both and how should I
9条回答
  •  没有蜡笔的小新
    2020-11-22 04:28

    Overview

    • const guarantees that a program does not change an object’s value. However, const does not guarantee which type of initialization the object undergoes.

      Consider:

      const int mx = numeric_limits::max();  // OK: runtime initialization
      

      The function max() merely returns a literal value. However, because the initializer is a function call, mx undergoes runtime initialization. Therefore, you cannot use it as a constant expression:

      int arr[mx];  // error: “constant expression required”
      
    • constexpr is a new C++11 keyword that rids you of the need to create macros and hardcoded literals. It also guarantees, under certain conditions, that objects undergo static initialization. It controls the evaluation time of an expression. By enforcing compile-time evaluation of its expression, constexpr lets you define true constant expressions that are crucial for time-critical applications, system programming, templates, and generally speaking, in any code that relies on compile-time constants.

    Constant-expression functions

    A constant-expression function is a function declared constexpr. Its body must be non-virtual and consist of a single return statement only, apart from typedefs and static asserts. Its arguments and return value must have literal types. It can be used with non-constant-expression arguments, but when that is done the result is not a constant expression.

    A constant-expression function is meant to replace macros and hardcoded literals without sacrificing performance or type safety.

    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)
    

    Constant-expression objects

    A constant-expression object is an object declared constexpr. It must be initialized with a constant expression or an rvalue constructed by a constant-expression constructor with constant-expression arguments.

    A constant-expression object behaves as if it was declared const, except that it requires initialization before use and its initializer must be a constant expression. Consequently, a constant-expression object can always be used as part of another constant expression.

    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
    

    Constant-expression constructors

    A constant-expression constructor is a constructor declared constexpr. It can have a member initialization list but its body must be empty, apart from typedefs and static asserts. Its arguments must have literal types.

    A constant-expression constructor allows the compiler to initialize the object at compile-time, provided that the constructor’s arguments are all constant expressions.

    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
    

    Tips from the book Effective Modern C++ by Scott Meyers about constexpr:

    • constexpr objects are const and are initialized with values known during compilation;
    • constexpr functions produce compile-time results when called with arguments whose values are known during compilation;
    • constexpr objects and functions may be used in a wider range of contexts than non-constexpr objects and functions;
    • constexpr is part of an object’s or function’s interface.

    Source: Using constexpr to Improve Security, Performance and Encapsulation in C++.

提交回复
热议问题