当前位置: 首页 > 知识库问答 >
问题:

constexpr和const有什么区别?

微生令雪
2023-03-14

consteprconst之间有什么区别?

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

共有3个答案

微生德泽
2023-03-14

>

考虑:

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

函数max()只返回一个字面值。但是,由于初始化器是一个函数调用mx会进行运行时初始化。因此,您不能将其用作常量表达式:

int arr[mx];  // error: “constant expression required”

constepr是一个新的C 11关键字,它使您不再需要创建宏和硬编码文本。在某些条件下,它还保证对象进行静态初始化。它控制表达式的计算时间。通过强制执行表达式的编译时计算,constepr允许您在依赖编译时常量的任何代码中定义对时间关键型应用程序、系统编程、模板至关重要的真正常量表达式。

常量表达式函数是声明为constexpr的函数。它的主体必须是非虚拟的,并且仅由一条返回语句组成,除了typedef和静态断言。它的参数和返回值必须具有文字类型。它可以与非常量表达式参数一起使用,但这样做的结果不是常量表达式。

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

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)

常量表达式对象是声明为constexpr的对象。它必须用常量表达式或由带有常量表达式参数的常量表达式构造函数构造的右值初始化。

常量表达式对象的行为就像声明了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

常量表达式构造函数是声明为constexpr的构造函数。它可以有一个成员初始化列表,但除了typedef和静态断言之外,它的主体必须为空。它的参数必须具有文字类型。

常量表达式构造函数允许编译器在编译时初始化对象,前提是构造函数的参数都是常量表达式。

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

斯科特·梅耶斯(Scott Meyers)的《有效现代C语言》(Effective Modern C)一书中关于constepr的提示:

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

来源:使用constepr提高C语言的安全性、性能和封装性。

山鸿彩
2023-03-14

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

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

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

莘羽
2023-03-14

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

>

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

    constepr声明了一个对象,该对象适合在标准所称的常量表达式中使用。但请注意,constepr并不是唯一的方法。

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

    >

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

    可以与成员函数和非成员函数以及构造函数一起使用。它声明函数适合在常量表达式中使用。只有当函数满足某些条件(7.1.5/3,4)时,编译器才会接受它,最重要的是()

    • 函数体必须是非虚拟的,并且非常简单:除了typedef和静态断言,只允许一个返回语句。对于构造函数,只允许初始化列表、typedef和静态断言。(=默认=删除也是允许的。)
    • 作为C 14,规则是更宽松的,什么是允许的,因为从那时起,里面有一个Constexr函数:ASM声明,一个goto语句,一个标签以外的语句大小写默认,try-块,一个非文字类型的变量的定义,一个静态或线程存储持续时间的变量的定义,一个不执行初始化的变量的定义。
    • 参数和返回类型必须是文字类型(即,一般来说,非常简单的类型,通常是标量或聚合)

    如上所述,constexr声明对象和函数都适合在常量表达式中使用。常量表达式不仅仅是常量:

    >

  • 它可以用于需要编译时计算的地方,例如模板参数和数组大小说明符:

      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
    

    但请注意:

    将某个东西声明为constepr并不一定保证它会在编译时被评估。它可以用于这种情况,但也可以用于在运行时进行评估的其他地方。

    对象可能适合在常量表达式中使用,而无需声明constexpr。例子:

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

    这是可能的,因为N是常量,并在声明时用文字初始化,满足常量表达式的条件,即使它没有声明constexr

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

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

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

    >

     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
     }
    

    什么时候可以/应该同时使用,constconstepr

    A.在对象声明中。当两个关键字都引用要声明的同一个对象时,这是不必要的constepr意味着const

    constexpr const int N = 5;
    

    是一样的

    constexpr int N = 5;
    

    但是,请注意,在某些情况下,每个关键字都指向声明的不同部分:

    static constexpr int N = 3;
    
    int main()
    {
      constexpr const int *NP = &N;
    }
    

    在这里,NP被声明为地址常量表达式,即本身是常量表达式的指针。(当地址是通过将地址运算符应用于静态/全局常量表达式而生成时,这是可能的。)在这里,需要ConstexrconstConstexr总是指被声明的表达式(这里是NP),而constint(它声明指针到const)。删除const将使表达式非法(因为(a)指向非const对象的指针不能是常量表达式,以及(b)

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

    constexpr void f();
    

    需要声明为

    constexpr void f() const;
    

    在C 14下,以便仍然可用作常量函数。

  •  类似资料:
    • 问题内容: 在学习电子时,我发现了两种获取BrowserWindow对象的方法。 和 和之间有什么区别? 我不明白为什么可以使用。我是否想念有关JS的重要信息? 问题答案: 这两段代码是等效的,但是第一段代码使用的ES6分解分配要短一些。 这是一个如何工作的简单示例:

    • 我最近读到了关键字,我很困惑!我找不到和关键字之间的任何区别,我的意思是我们可以使用它们来创建一个不可变的变量,还有什么我遗漏的吗?

    • 我最近读到了关于const关键字的文章,我很困惑!我找不到const和val关键字之间的任何区别,我的意思是我们可以使用它们来生成一个不可变的变量,还有什么我遗漏的吗?

    • 问题内容: 我不知道是什么样的区别,并在 ES6 。两者都是块作用域的,如以下代码中的示例所示: 在ES5中,输出为: 但是在ES6中它将是: 我想知道为什么 ES6 允许更改值,问题是为什么我们现在应该使用’const’?我们可以用“ let”代替吗? 注意 :jsbin可以用于测试,选择 JavaScript 运行 ES5 代码,并选择 Traceur 使用 ES6 功能运行它。 问题答案:

    • 本文向大家介绍说下var、let和const有什么区别?相关面试题,主要包含被问及说下var、let和const有什么区别?时的应答技巧和注意事项,需要的朋友参考一下 var定义变量,let定义常量,const定义变量。 var存在变量提升,let和const不存在变量提升 let,const部分说反了吧...

    • 这是c primer中的代码: 从