`constexpr`和`const`之间的区别 [英] Difference between `constexpr` and `const`

查看:288
本文介绍了`constexpr`和`const`之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

constexpr const 之间有什么区别?




  • 我什么时候只能使用其中一个?

  • 我什么时候可以同时使用,我应该如何选择?


解决方案

基本含义和语法



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




  • const 声明一个对象为常量。这意味着保证,一旦初始化,该对象的值不会改变,并且编译器可以利用这个事实进行优化。


  • constexpr c $ c>声明一个对象适用于在标准调用常量表达式。但请注意, constexpr 不是这样做的唯一方法。




应用于功能时,基本区别是:




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


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




    • 函数体必须是非虚拟的并且非常简单:除了typedef和静态断言,只允许一个返回语句。在构造函数的情况下,只允许初始化列表typedefs和静态assert。 ( = default = delete )。

    • 参数和返回类型必须是字面类型(即,一般来说,非常简单的类型,通常是标量或聚合)




常量表达式



如上所述, constexpr 声明这两个对象以及适用于常量表达式的函数。常量表达式不仅仅是常数:




  • 它可以用在需要编译时评估的地方,模板参数和数组大小说明符:

      template< int N& 
    class fixed_size_list
    {/*...*/};

    fixed_size_list< X>米尔斯特// X必须是一个整数常量表达式

    int numbers [X]; // X必须是整数常数表达式


  • 但是请注意:




    • 声明为 constexpr 不一定保证将在编译时进行评估。

      >对象可以适用于常量表达式,而不被声明为 constexpr 。示例:

        int main()
      {
      const int N = 3;
      int numbers [N] = {1,2,3}; // N是常量表达式
      return 0;
      }




    N 是常数,并且在声明时使用文字初始化,满足常量表达式的条件,即使未声明 constexpr




所以我什么时候必须使用 constexpr




  • 上面的c $ c> N 可以用作常量表达式而不被声明为 constexpr 。对于所有对象都是如此:




    • const

    • 整数或枚举类型

    • 在声明时初始化一个自身为常量表达式的表达式





    [这是由于§5.19/ 2:常量表达式不能包含子表达式因为理查德·史密斯纠正了我早先的声明,这对于所有的文字类型都是正确的。]


  • 函数适用于常量表达式,必须 c> constexpr ;仅仅满足常数表达式函数的标准是不够的。示例:

     模板< 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不是constexpr
    return 0;
    }




可以/我应该同时使用 const constexpr 在一起吗?



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

  constexpr const int N = 5; 

相同

  constexpr int N = 5;但是,请注意,可能存在关键字各自引用声明的不同部分的情况: 

/ p>

  static constexpr int N = 3; 

int main()
{
constexpr const int * NP =& N;
return 0;
}

这里, NP 被声明为地址常量表达式,即本身是常数表达式的指针。 (当通过将地址运算符应用到静态/全局常量表达式生成地址时,这是可能的)。这里, constexpr const 是必需的: constexpr 始终引用要声明的表达式(此处 NP ), c $ c> const 指的是 int (它声明一个指向const的指针)。删除 const 会使表达式非法(因为(a)指向非const对象的指针不能是常量表达式,并且(b) & N 实际上是指向常数的指针)。



B。在成员函数声明中。在C ++ 11中, constexpr 还意味着 const 但是,这在C ++ 14中可能会改变。根据当前的草案, constexpr 将意味着 const 功能,由于建议对§7.1.5/ 8进行更改。因此,在C ++ 11下声明的成员函数为

  constexpr void f 

必须声明为

  constexpr void f()const; C ++ 14下的

,以便仍然可以用作 const 函数。 最好将 constexpr 的成员函数标记为 const ,以避免必须更改大量代码






(†) c $ c> constexpr 函数可能会放宽对于C ++ 14。 Richard Smith的提案最近已发布被引入C ++ 14草案


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 choose one?

解决方案

Basic meaning and syntax

Both keywords can be used in the declaration of objects as well as functions. The basic difference when applied to objects is this:

  • const declares an object as constant. This implies a guarantee that, once initialized, the value of that object won't change, and the compiler can make use of this fact for optimizations. It also helps prevent the programmer from writing code that modifies objects that were not meant to be modified after initialization.

  • constexpr declares an object as fit for use in what the Standard calls constant expressions. But note that constexpr is not the only way to do this.

When applied to functions the basic difference is this:

  • const can only be used for non-static member functions, not functions in general. It gives a guarantee that the member function does not modify any of the non-static data members.

  • constexpr can be used with both member and non-member functions, as well as constructors. It declares the function fit for use in constant expressions. The compiler will only accept it if the function meets certain criteria (7.1.5/3,4), most importantly (†):

    • The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single return statement is allowed. In the case of a constructor, only an initialization list, typedefs and static assert are allowed. (= default and = delete are allowed, too, though.)
    • The arguments and the return type must be literal types (i.e., generally speaking, very simple types, typically scalars or aggregates)

Constant expressions

As said above, constexpr declares both objects as well as functions as fit for use in constant expressions. A constant expression is more than merely constant:

  • It can be used in places that require compile-time evaluation, for example, template parameters and array-size specifiers:

    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
    

  • But note:

    • Declaring something as constexpr does not necessarily guarantee that it will be evaluated at compile time. It can be used for such, but it can be used in other places that are evaluated at run-time, as well.

    • An object may be fit for use in constant expressions without being declared constexpr. Example:

      int main()
      {
        const int N = 3;
        int numbers[N] = {1, 2, 3};  // N is constant expression
        return 0;
      }
      

    This is possible because N, being constant and initialized at declaration time with a literal, satisfies the criteria for a constant expression, even if it isn't declared constexpr.

So when do I actually have to use constexpr?

  • An object like N above can be used as constant expression without being declared constexpr. This is true for all objects that are:

    • const
    • of integral or enumeration type and
    • initialized at declaration time with an expression that is itself a constant expression

    [This is due to §5.19/2: A constant expression must not include a subexpressions that involves "an lvalue-to-rvalue modification unless […] a glvalue of integral or enumeration type […]" Thanks to Richard Smith for correcting my earlier claim that this was true for all literal types.]

  • For a function to be fit for use in constant expressions, it must be explicitly declared constexpr; it is not sufficient for it merely to satisfy the criteria for constant-expression functions. Example:

    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;
    }
    

When can I / should I use both, const and constexpr together?

A. In object declarations. This is never necessary when both keywords refer to the same object to be declared. constexpr implies const.

constexpr const int N = 5;

is the same as

constexpr int N = 5;

However, note that there may be situations when the keywords each refer to different parts of the declaration:

static constexpr int N = 3;

int main()
{
  constexpr const int *NP = &N;
  return 0;
}

Here, NP is declared as an address constant-expression, i.e. an pointer that is itself a constant expression. (This is possible when the address is generated by applying the address operator to a static/global constant expression.) Here, both constexpr and const are required: constexpr always refers to the expression being declared (here NP), while const refers to int (it declares a pointer-to-const). Removing the const would render the expression illegal (because (a) a pointer to a non-const object cannot be a constant expression, and (b) &N is in-fact a pointer-to-constant).

B. In member function declarations. In C++11, constexpr implies const also for member functions. However, this is likely to change in C++14. According to the current drafts, constexpr will imply const only for objects, not for member functions, due to a proposed change to §7.1.5/8. Hence, a member function declared under C++11 as

constexpr void f();

will have to be declared as

constexpr void f() const;

under C++14 in order to still be usable as a const function. Best mark your constexpr member functions as const even now so as to avoid having to change a lot of code later on.


(†) The conditions for acceptable constexpr functions will probably be relaxed for C++14. A proposal by Richard Smith has recently been adopted into the C++14 draft.

这篇关于`constexpr`和`const`之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆