C++ constexpr
1、constexpr
1、const与constexpr:
const: 承若不改变这个值,主要用于说明接口,这样在把变量传入函数时就不必担心变量会在函数内被改变了,编译器负责确认并执行const的承若。
constexpr:在编译时求值,主要用来说明常量,作用是允许将数据置于只读内存中以及提升性能。
常量表达式指由编译器求值的表达式。
//使用const定义常量
const int x = 7; //
const string s = "hello"; //
const int y = sqrt(x);
//使用constexpr定义常量
constexpr int xx = x; //OK
constexpr string ss = s; //错误:string不是字面值常量类型
constexpr int yy = y; //错误:sqrt(x)不是constexpr函数
以常量表达式初始化的const可以用在常量表达式中,与constexpr不同的是,const可以用非常量表达式初始化,但此时该const将不能用作常量表达式。
通常情况下,当定义简单的常量时,constexpr比const要好。
2、字面值常量类型
struct Point
{
int x, y, z;
constexpr Point up(int d)
{
return {x, y, z + d};
}
constexpr Point move(int dx, int dy)
{
return {x + dx, y + dy};
}
};
含有constexpr构造函数的类称为字面值常量类型。构造函数必须足够简单才能声明为constexpr,即它的函数体必须为空且所有成员都是用潜在的常量表达式初始化的。
对于成员函数来说,constexpr隐含了const的意思。所以下面这种写入是没有必须要的:
constexpr Point move(int dx, int dy) const
{
return {x + dx, y + dy};
}
通过使用字面值类型, 我们可以令constexpr函数适应用户自定义的类型。
3、constexpr 函数
在函数定义中出现constexpr时,它的含义:如果给定了常量表达式作为实参,则该函数应该能用在常量表达式中。
在对象定义中出现constexpr时,它的含义:在编译时对初始化器求值。
constexpr int fac(int n)
{
return (n > 1) ? n * fac(n - 1) : 1;
}
void f(n)
{
int f5 = fac(5); //可能在编译期求值
int fn = fac(n); //在运行时求值(n是变量)
constexpr int f6 = fac(6); //必须在编译期求值
constexpr int fnn = fac(n); //错误:无法在编译期求值
char a[fac(4)]; //数组的尺寸必须是常量,fac(4)是常量
char a2[fac(n)]; //错误:数组的尺寸必须是常量,而n是变量
}
函数必须足够简单才能在编译期求值:
- constexpr函数必须包含一条独立的return语句。
- constexpr不能有循环,也不能有局部变量。
- constexpr函数不能有副作用,constexpr函数应该是一个纯函数。
以下是一些错误的示例:
int glob;
constexpr void bad1(int a) //错误: constexpr函数不能使void
{
glob = a; //错误: constexpr函数有副作用
}
constexpr int bad2(int a)
{
if( a > 0) return a; //错误: constexpr有if语句
else return -a;
}
constexpr int bad3(int a)
{
int sum = 0; //错误: 有局部变量
for(int i = 0; i < a; ++i) //错误: 有for循环
sum += fac(i);
return sum;
}
4、constexpr与引用
constexpr函数不允许有副作用,因此我们不能向非局部对象写入内容,反过来说,只要我们不向非局部对象写入内容,就能使用它。
示例:
constexpr int ftb[]{1, 2, 3, 5,8, 13};
constexpr int fib(int n)
{
return (n < sizeof(ftb)/sizeof(*ftb)) ? ftb[n] : ftb[sizeof(ftb)/sizeof(*ftb) - 1];
}
constexpr 函数可以接收引用实参,尽管它不能通过这些引用写入内容,但是const引用参数同样有用。
template<>
class complex<float>
{
public:
//...
explicit constexpr complex(const complex<double> &);
//...
}
//
constexpr complex<float> z{2.0};
//其中逻辑上用于存储const引用实参的临时变量成了编译器内部可用的一个值
5、条件求值
constexpr函数之外的条件表达式不会在编译期求值。
constexpr int check(int i)
{
return (low <= i && i < high) ? i : throw out_of_range();
}
//其中我们假设low和high值是设计时未知,而编译时已知的参数。
constexpr int low = 0;
constexpr int high = 99;
C++ constexpr的更多相关文章
- C++11特性——变量部分(using类型别名、constexpr常量表达式、auto类型推断、nullptr空指针等)
#include <iostream> using namespace std; int main() { using cullptr = const unsigned long long ...
- [c++] constexpr and literal class
稀奇古怪的新特性,菜鸟在此啄上一啄. 1. When should literal classes be used in C++? 2. int i; // not constant const ...
- C++之内联函数与constexpr
inline 函数 规模小,流程直接且频繁调用 cout<<shortString(s1,s2)<<endl; = cout<<(s1.size()<s2.s ...
- Item 15: 只要有可能,就使用constexpr
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 如果说C++11中有什么新东西能拿"最佳困惑奖" ...
- c++基础 - constexpr
const expression常量表达式,指值不会改变,并且在编译过程中就能得到计算结果的表达式. 复杂系统难以分辨一个初始值是否是常量表达式,因此提出constexptr以提示编译器,用来验证变量 ...
- constexpr和常量表达式
常量表达式:值不会改变并且在编译过程就能得到计算结果的表达式. 字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式. 一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同 ...
- 【C++】C++中const与constexpr的比较
先说结论相同点:const和consexpr都是用来定义常量的.不同点:const声明的常量,初始值引用的对象不一定是一个常量:constexpr声明的常量,初始值一定是常量表达式. constexp ...
- C++11 constexpr常量表达式
常量表达式函数 要求: 函数体内只有单一的return返回语句 例如: constexpr int data() { const int i=1; //含有除了return以外的语句 return i ...
- 常量表达式和constexpr(c++11)
常量表达式 常量表达式是指值不会改变且在编译阶段就能得到计算结果的表达式(两点要求) ; //是常量表达式 ; //是常量表达式 "; const int siz=s.size(); //不 ...
- c++ 11 游记 之 decltype constexpr
title: c++ 11 游记 1 keyword :c++ 11 decltype constexpr 作者:titer1 zhangyu 出处:www.drysaltery.com 联系:130 ...
随机推荐
- T3
T3构造图
- python函数的参数问题
语法 def functionname( parameters ): "函数_文档字符串" function_suite return [expression] 参数问题 必备参数 ...
- .net sqlite 内存溢出 问题的分析与解决。
一个小的工具网站,用了sqlite数据库,在并发小的情况一切正常,但是并发量上来之后,就报"out of memory"错误了. 分析了代码,就是很简单的根据一个条件取一段数据,并 ...
- 【原创实现】C 多线程入门Demo CAS Block 2种模式实现
分Cas和Block模式实现了demo, 供入门学习使用,代码全部是远程实现. 直接上代码: /* ================================================== ...
- 3,、maven修改jar包下载为国内镜像下载地址
maven 默认的中央仓库是在国外的服务器,下载速度慢,有时候稍不注意就下载出错 通常我将maven的中央仓库修改为阿里云的地址,下载速度很快体验非常好 修改conf下的setting.xml文件 在 ...
- 阶段3 1.Mybatis_06.使用Mybatis完成DAO层的开发_4 Mybatis中使用Dao实现类的执行过程分析-查询方法
delete方法没有并SqlSession的delete方法,而是调用的Upadte方法. 在测试类这里加断点. 实际的方法体内也加断点 运行测试方法,选择debug的方式 走到断点这里.会看到fac ...
- 2018.03.27 python pandas merge join 使用
#2.16 合并 merge-join import numpy as np import pandas as pd df1 = pd.DataFrame({'key1':['k0','k1','k2 ...
- CentOS 7.3下使用yum安装MySQL
CentOS 7的yum源中默认是没有mysql的,要先下载mysql的repo源. 1.下载mysql的repo源 $ wget http://repo.mysql.com/mysql-commun ...
- Scratch少儿编程系列:(一)版本的选择及安装
工欲善其事必先利其器,为了使用Scratch,首先要到官网上下载相关软件. 官网链接地址为:https://scratch.mit.edu/download,我用的是Windows系统,下载对应的安装 ...
- java中线程同步的理解(非常通俗易懂)
转载至:https://blog.csdn.net/u012179540/article/details/40685207 Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运 ...