常量表达式是什么_const常量

常量表达式是什么_const常量常量表达式值(constant-expressionvalue)。通常情况下,常量表达式值必须被一个常量表达式赋值,而跟常量表达式函数一样,常量表达式值在使用前必须被初始化。一、常量表达式1.1运行时常量性与编译时常量性在C++中,我们常常会遇到常量的概念。常量表示该值不可修改,通常是通过const关键字来修饰的。比如:constinti=3;const还可以修饰函数参数、函数返回值、函数本身、类等。在不同的使用条件下,const有不同的意义,不过大多数情况下,const描述的都

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

常量表达式值(constant-expression value)。通常情况下,常量表达式值必须被一个常量表达式赋值,而跟常量表达式函数一样,常量表达式值在使用前必须被初始化。

一、常量表达式

1.1 运行时常量性与编译时常量性

在C++中,我们常常会遇到常量的概念。常量表示该值不可修改,
通常是通过const关键字来修饰的。比如:

const int i = 3;

const还可以修饰函数参数、函数返回值、函数本身、类等。在不同的使用条件下,const有不同
的意义,不过大多数情况下,const描述的都是一些“运行时常量性”的概念,即具有运行时数据的不可更改性。不过有的时候,我们需要的却是编译时期的常量性,这是const关键字无法保证的。

#include <iostream>
#include <string>
using namespace std;

const int GetConst() { 
    return 1; }
void Constless(int cond) { 
   
int arr[GetConst()] = { 
   0}; // 无法通过编译
enum { 
    e1 = GetConst(), e2 }; // 无法通过编译
switch (cond) { 
   
case GetConst(): // 无法通过编译
break;
default:
break;
}
}

int main()
{ 
   
    cout<< GetConst()<< endl;
}

bash-4.4$ g++ constexpr.cpp -o expr && ./expr
constexpr.cpp: In function ‘void Constless(int)’:
constexpr.cpp:8:21: error: call to non-‘constexpr’ function ‘const int GetConst()’
 enum { 
    e1 = GetConst(), e2 }; // 无法通过编译
             ~~~~~~~~^~
constexpr.cpp:8:21: error: call to non-‘constexpr’ function ‘const int GetConst()’
constexpr.cpp:8:22: error: enumerator value for ‘e1’ is not an integer constant
 enum { 
    e1 = GetConst(), e2 }; // 无法通过编译
                      ^
constexpr.cpp:10:14: error: call to non-‘constexpr’ function ‘const int GetConst()case GetConst(): // 无法通过编译
      ~~~~~~~~^~
constexpr.cpp:10:14: error: call to non-‘constexpr’ function ‘const int GetConst()

我们定义了一个返回常数1的函数GetConst。我们使用了const关键字修饰了返回类型。不过编译后我们发现,无论将GetConst的结果用于需要初始化数组Arr的声明中,还是用于匿名枚举中,或用于switch-case的case表达式中,编译器都会报告错误。发生这样错误的原因如我们上面提到的一样,这些语句都需要的是编译时期的常量值。而const修饰的函数返回值,只保证了在运行时期内其值是不可以被更改的。这是两个完全不同的概念。

1.2 如何获得编译期常量

简单粗暴的做法 :使用C中的宏替代GetConst函数。

#define GetConst 1

C++11中对编译时期常量的回答是constexpr,即常量表达式(constant expression)。

constexpr int GetConst() { 
    return 1; }

即在函数表达式前加上constexpr关键字即可。有了常量表达式这样的声明,编译器就可以在编译时期对GetConst表达式进行值计算(evaluation),从而将其视为一个编译时期的常量(虽然编译器不一定
这么做,但至少从语法效果上看是这样,我们会在后面叙述)。

#define GetConst 1

#include <iostream>
#include <string>
using namespace std;

#define GetConst 1

//const int GetConst() { return 1; }

void Constless(int cond) { 
   
int arr[GetConst] = { 
   0}; 
enum { 
    e1 = GetConst, e2 }; 
switch (cond) { 
   
case GetConst:
    cout<< GetConst <<endl;
break;
default:
break;
}
}

int main()
{ 
   
    //cout<< GetConst()<< endl;
    Constless(1);
}

constexpr

#include <iostream>
#include <string>
using namespace std;

constexpr int GetConst() { 
    return 1; }
void Constless(int cond) { 
   
int arr[GetConst()] = { 
   0};
enum { 
    e1 = GetConst(), e2 };
switch (cond) { 
   
case GetConst():
break;
default:
break;
}
}

int main()
{ 
   
    cout<< GetConst()<< endl;
}

2.1 常量表达式函数

通常我们可以在函数返回类型前加入关键字constexpr来使其成为常量表达式函数。不过并非所有的函数都有资格成为常量表达式函数。事实上,常量表达式函数的要求非常严格,总结起来,大概有以下几点:
·函数体只有单一的return返回语句。
·函数必须返回值(不能是void函数)。
·在使用前必须已有定义。
·return返回语句表达式中不能使用非常量表达式的函数、全局数据,且必须是一个常量表达式

首先是常量表达式函数中最为明显的限制,就是要求函数体中只有一条语句,且该条语句必须是return语句。
这就意味着形如:

constexpr int data() { 
    const int i = 1; return i; }

这样的多条语句的写法是无法通过编译的。不过一些不会产生实际代码的语句在常量表达式函数中使用下,倒不会导致编译器的“抱怨”。我们可以看看如下static_assert的情况:

constexpr int f(int x){ 
   
static_assert(0 == 0, "assert fail.");
return x;
}

该例子能够通过编译。而其他的,比如using指令、typedef等也通常不会造成问题。

第二点约束,则是常量表达式必须返回值。形如constexpr void f(){}这样的不返回值的函数就不能是常量表达式。当然,其原因也很明显,因为无法获得常量的常量表达式是不被认可的。
第三点约束是常量表达式函数在使用前必须被定义。对于普通函数而言,调用函数只需要有函数声明就够了,但常量表达式函数的使用则有所不同。这里读者应该注意常量表达式“使用”和“调用”的区别,前者
讲的是编译时的值计算,而后者讲的是运行时的函数调用

constexpr int f();
int a = f();
const int b = f();
constexpr int c = f(); //无法通过编译 f先声明,此时还没有实现
constexpr int f() { 
    return 1; }
constexpr int d = f();

在a和b的定义中,编译器会将f()转换为一个函数调用,
而在c的定义中,由于其是一个常量表达式值,因此会要求编译器进行编译时的值计算。
这时候由于f常量表达式还没有定义,就会导致编译错误。
而d的定义则没有问题,因为f的定义已经有了。

第四点非常重要,常量表达式中,也不能使用非常量表达式的函数。形如

const int e(){ 
    return 1;}
constexpr int g(){ 
    return e(); }

或者形如

int g = 3;
constexpr int h() { 
    return g; }

的常量表达式定义是不能通过编译的。这样做的意义也比较明显,即如果我们要使得g()是一个编译时的常量,那么其return表达式语句就不能包含运行时才能确定返回值的函数。只有这样,编译器才能够在编译时进行常量表达式函数的值计算。
当然,作为一个常量表达式函数,return的表达式需要是一个常量表达式也是天经地义的事情。一些危险的操作,比如赋值的操作在常量表达式中也是不允许的,形如

constexpr int k(int x) { 
    return x = 1; }

的语句也是无法通过C++11编译器的编译的。

3.1 常量表达式值

常量表达式值(constant-expressionvalue)。通常情况下,常量表达式值必须被一个常量表达式赋值,而跟常量表达式函数一样,常量表达式值在使用前必须被初始化。而使用constexpr声明的数据最常被问起的问题是,下列两条语句有什么区别:

const int i = 1;
constexpr int j = 1;

事实上,两者在大多数情况下是没有区别的。不过有一点是肯定的,就是如果i在全局名字空间中,编译器一定会为i产生数据。而对于j,如果不是有代码显式地使用了它的地址,编译器可以选择不为它生成数据,而仅将其当做编译时期的值(是不是想起了光有名字没有产生数据的枚举值,以及不会产生数据的右值字面常量?事实上,它们也都只是编译时期的常量)。

而对于自定义类型的数据,要使其成为常量表达式值的话,则不像内置类型这么简单。C++11标准中,constexpr关键字是不能用于修饰自定义类型的定义的。比如下面这样的类型定义和使用:

constexpr struct MyType { 
   int i; }
constexpr MyType mt = { 
   0};

在C++11中,就是无法通过编译的。正确地做法是,定义自定义常量构造函数(constent-expression constructor)。

struct MyType { 
   
constexpr MyType(int x): i(x){ 
   }
int i;
};
constexpr MyType mt = { 
   0};

代码清单6-4中,我们对MyType的构造函数进行了定义。不过在定
义前,我们加上了constexpr关键字。通过这样的定义,MyType类型的
constexpr的变量mt的定义就可以通过编译了。
常量表达式的构造函数也有使用上的约束,主要的有以下两点:
·函数体必须为空。
·初始化列表只能由常量表达式来赋值。

在C++11中,不允许常量表达式作用于virtual的成员函数。这个原因也是显而易见的,
virtual表示的是运行时的行为,与“可以在编译时进行值计算”的constexpr的意义是冲突的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/188901.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • html左侧浮动广告代码,jQuery 浮动广告实现代码[通俗易懂]

    html左侧浮动广告代码,jQuery 浮动广告实现代码[通俗易懂]实现方法:浮动广告#qqonline{background-color:red;border:1pxsolid#fcc;position:absolute;top:100px;left:16px;width:100px;height:120px;}#qqonline1{background-color:red;border:1pxsolid#fcc;position:absolute;…

  • Pytest(6)重复运行用例pytest-repeat

    Pytest(6)重复运行用例pytest-repeat前言平常在做功能测试的时候,经常会遇到某个模块不稳定,偶然会出现一些bug,对于这种问题我们会针对此用例反复执行多次,最终复现出问题来。自动化运行用例时候,也会出现偶然的bug,可以针对单个用例,

  • 2022新UI美观发卡网源码下载+功能强大且齐全

    2022新UI美观发卡网源码下载+功能强大且齐全正文:程序没有更多的介绍,总的来说就是2022最新版本的,美观功能齐全无BUG,上传程序后,运行目录public,伪静态thinkPHP,域名/install.php进行安装,就是这么简单哈,程序没有马赛克的演示图我就放压缩包了,大家自行去查看吧。程序:lanzou.com/ieWX005hj7dc图片:…

  • goland激活码最新-激活码分享

    (goland激活码最新)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.htmlTR0LFTT656-eyJsa…

  • qq视频资源是什么_qq代码视频教程

    qq视频资源是什么_qq代码视频教程QQ视频资源裂变源码有哪些功能对于2021年网赚引流最快变现的一些思路qq资源!已解锁全部!点击进入观赏!这个是分享以后得卡片标题内容这个系统有2个版本,第一调用单个视频资源链接(支持mp4,m3u8格式),第二个版本支持观看10-60秒后强制分享弹窗下上图片位置带自定义图片广告跳转,跳转链接可批量留多个裂变网页链接达到裂变式框架“`…

  • Intellij IDEA 2021 Maven 配置指南「建议收藏」

    Intellij IDEA 2021 Maven 配置指南「建议收藏」Maven是Java一个不错的项目管理工具,但在IntellijIDEA软件中配置它却并非一件省心的事情,不少小萌新会配置失败。所以,我打算分享这篇教程,帮助萌新们在IntellijIDEA中配置好Maven~

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号