常量表达式和constexpr(c++11)
常量表达式
常量表达式是指值不会改变且在编译阶段就能得到计算结果的表达式(两点要求)
const int max_files = ; //是常量表达式
const int limit = max_file + ; //是常量表达式
string s="";
const int siz=s.size(); //不是常量表达式
int staff_size = ; //不是常量表达式
const int sz = get_size(); //不是常量表达式,因为尽管sz本身是一个常量,但是它的值直到程序运行时才能获得
constexpr(c++11)
c++11允许将变量声明为constexpr类型让编译器来验证变量是否为一个常量表达式
constexpr int mf = ;
constexpr int limit = mf + ;
constexpr int sz = get_size(); //只有当get_size()是一个constexpr函数时才是正确的声明
const变量 和 constexpr 变量之间的主要区别
1.const 变量的初始化可以延迟到运行时,而 constexpr 变量必须在编译时进行初始化:
const int sz = get_size(); //正确的声明,但是sz不是常量表达式
constexpr int sz = get_size(); //只有当get_size()是一个constexpr函数时才是正确的声明
2.constexpr声明中如果定义了一个指针,限定符constexpr只对指针有效,与指针所指的对象无关:
const int* p = nullptr; //p是一个指向整型常量的指针
constexpr int* q = nullptr; //q是一个指向整型的常量指针
constexpr const int* r = nullptr; //r是一个指向整型常量的常量指针
constexpr函数
用限定符constexpr修饰函数,使之用于常量表达式中,constexpr函数有这么几个特性:
1.函数的返回类型和所有的形参类型都是字面值类型
2.函数体中只有一条语句,而且只能是一条return语句(但其实也是可以包含其他语句的,只要这些语句在程序运行时不执行任何操作就行,如:空语句、类型别名、using声明)
constexpr int new_sz()
{
return ;
}
3.编译器其实也允许constexpr函数的返回值和形参不是字面值(编译器有时可忽略函数的constexpr属性)
constexpr int get_size(int a)
{
return a;
} int main()
{
int size = ;
int y = get_size(size); //正确,编译器此时忽略函数的constexpr属性,因为y是非constexpr的,可以不要求get_size是constexpr的
constexpr int z = get_size(size); //错误!!! int arr1[get_size()]; //正确
int arr2[get_size(size)]; //错误,数组的大小要求是常量表达式 return ;
}
4.constexpr函数自带inline属性
5.inline函数和constexpr函数可以在程序中多次定义,一般定义在头文件中,但是多个定义必须完全一致:
现在假设我们有2个cpp文件和一个.h头文件:main.cpp(main函数在这个文件里), haha.cpp, xixi.h
main.cpp:
void fuck(){}
int main()
{
return ;
}
haha.cpp:
void fuck(){}
如果只编译main.cpp的话,是不会有重复定义的错误的。但是如果同时编译main.cpp和haha.cpp的话,那就会有重复定义错误。IDE一般都是会默认编译所有文件。
好,那能不能只定义在.h头文件里,然后另外两个cpp文件单纯include?
main.cpp:
#include "xixi.h" int main()
{
return ;
}
haha.cpp:
#include "xixi.h"
xixi.h:
void fuck(){}
结果是也不行,因为include其实就是把xixi.h里面的东西拷到cpp里,结果跟上面那种是一样的,也是在link的时候报错。
好,那我又想了,不是有个什么#ifndef的东西吗?给我的xixi.h加上这个行不行,这样不就只有一个fuck函数的定义了吗?
#ifndef XIXI
#define XIXI
void fuck(){}
#endif
结果还是不行,依然报重复定义错误,所谓的防止头文件重复包含是对应一个cpp文件。也就是说,这个#ifndef可以保证在haha.cpp里,#ifndef里面的内容是唯一的,也能保证在main.cpp里是唯一的,但不能保证你在这个程序里(同时用到main.cpp和haha.cpp)是唯一的。
考虑下面这个例子:
main.cpp:
#include "xixi.h" int main()
{
return ;
}
haha.cpp:
#include "xixi.h"
xixi.h:
#ifndef XIXI
#define XIXI
void fuck(); //这是声明
#endif
xixi.cpp:
#include"xixi.h"
void fuck(){}//定义
这样将不会有重复定义的错误。因为include的头文件里面没有函数定义,只有声明,而同一个函数是可以多次声明。
再回到inline函数的展开,展开需要什么,需要函数体,所以inline函数要定义在头文件里。但最开始的几个错误例子说了,定义在头文件的函数定义被多个cpp文件include后会有重复定义的错误,怎么办呢?用inline关键字可以避免这个问题,指明inline,就不会有这个错误:
main.cpp:
#include "xixi.h" int main()
{
return ;
}
haha.cpp:
#include "xixi.h"
xixi.h:
inline void fuck(){}
这样也不会有重复定义的错误。
综上,inline函数有2个作用:
- 函数展开,避免函数调用开销,(用空间换时间)
- 定义在头文件的inline函数被多个cpp文件include不会产生重复定义(在程序可以被多次定义的意思不是说可以在文件里重复定义,其实是给inline函数做一个标记,假如有10个inline函数体,然后最后会删除剩下1份)
常量表达式和constexpr(c++11)的更多相关文章
- C++常量表达式、const、constexpr(C++11新增)的区别
常量表达式是指值不会改变且在编译过程中就能够得到计算结果的表达式,能在编译时求值的表达式. 程序先编译再运行: 在编译阶段, 编译器将在编译过程中把用到该常量的地方都全都替换为 常量的值. 但是常量 ...
- constexpr和常量表达式
常量表达式:值不会改变并且在编译过程就能得到计算结果的表达式. 字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式. 一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同 ...
- 第8课 常量表达式(constexpr)
一. const 和constexpr的区别 (一)修饰变量时,const为“运行期常量”,即运行期数据是只读的.而constexpr为“编译期”常量,这是const无法保证的.两者都是对象和函数接口 ...
- const限定符、constexpr和常量表达式------c++ primer
编译器将在编译过程中把用到const变量的地方都替换成对应的值,为了执行这种替换,编译器必须知道变量的初始值.如果程序包含多个文件,则那个用了const对象的文件都必须能访问到它的初始值才行.要做到这 ...
- C++11特性——变量部分(using类型别名、constexpr常量表达式、auto类型推断、nullptr空指针等)
#include <iostream> using namespace std; int main() { using cullptr = const unsigned long long ...
- C++11 constexpr常量表达式
常量表达式函数 要求: 函数体内只有单一的return返回语句 例如: constexpr int data() { const int i=1; //含有除了return以外的语句 return i ...
- constexpr与常量表达式(c++11标准)
关键字 constexpr 是C++11中引入的关键字,是指值不会改变并且在编译过程中就得到计算结果的表达式.(运行中得到结果的不能成为常量表达式,比如变量). 声明为constexpr的变量一定是一 ...
- C++11常量表达式
[C++11之常量表达式] 关键字:constexpr: 中文学名:常量表达式. constexpr用于把运行期计算放置在编译期. 使用constexpr有3个限制: 1.函数中只能有一个return ...
- constexpr和常量表达式的注意事项
1.常量表达式,是指其值不可改变,且在编译阶段就已经得出计算结果的表达式,例如字面值就是常量表达式. 2.判断是否是常量表达式,要关注数据类型是否是const类型,初始值是否是在编译阶段就得到的. 3 ...
随机推荐
- f5 SSL及证书
1.SSL卸载 1)在BIG-IP上终结SSL连接BIG-IP可以全面了解应用,可以使用iRules, Profiles等,可以释放server的资源 2)包含:统一管理证书与密钥:支持基于硬件的关键 ...
- 【centos】centos安装g++
gcc在Centos下的安装:使用的是以下语句:yum install gcc 以为安装g++,类似的应该使用:yum install g++ 可是提示:command is not found 查询 ...
- sql查询 !='' 和 is not null的区别
select * from table where a is not null 会把有内容的和内容为空的都查出来而select * from table where a != '' 只会把有内容的查出 ...
- zookeeper 单机版配置
zookeeper :中间件,为分布式系统进行协调服务 作用于分布式系统,可以为大数据服务 支持java 和 C 客户端的api zookeeper 特性:一致性,数据会按照顺序分批入库: 原子性:数 ...
- 快速将磁盘的MBR分区方式改成GPT分区方式
1.按Shift + F10打开命令提示符. 2.diskpart 3.list disk(列出所有磁盘) 4.select disk 0(选择磁盘) 5.clean(格式化所选的磁盘) 7.conv ...
- threejs- z-fighting 问题(模型的重叠部位便不停的闪烁起来。这便是Z-Fighting问题)
Z-Buffer 在threejs中,使用深度缓冲(Z-Buffer)来完成场景可见性计算,即确定场景哪部分可见,哪部分不可见.深度缓冲(Z-Buffer)是一个二维数组,其中的每一个元素对应屏幕上的 ...
- 包含了重复的“Content”项。.NET SDK 默认包含你项目目录中的“Content”项。可从项目文件中删除这些项;如果希望将其显式包含在项目文件中,可将“EnableDefaultContentItems”属性设置为“false”
从.netcore 1.1 升级到2.0时遇到该问题. 参考http://www.cnblogs.com/xishuai/p/visual-studio-for-mac.html 根据提示可知(我是看 ...
- Materix3*3
][],][],][]) { ;i<;i++) { ;j<;j++) { res[i][j]= aa[i][] * bb[][j] + aa[i][] *bb[][j] + aa[i][] ...
- 1.maven安装配置
这段时间在做项目构建管理方面的工作,以前很多项目都是通过ant去构建的,虽然很早就接触过mavan,但是从没有系统的去学习过, 现在项目需要用maven来构建,我结合自己的心得整理一下放在博客上作为自 ...
- laravel 服务提供者介绍和使用
#安装传送门 安装composer,以及通过composer安装laravel #讲解使用 服务提供者这个具体表现都是围绕着依赖注入 在根目录config/app.php的providers中的数组中 ...