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 ...
随机推荐
- Java 简单工厂
在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的.但是在一些情况下, new操作符直接生成对象会带来一些问题.举例来说, 许多类型对象的创造需要一 ...
- 添加tomcat为启动服务/删除tomcat服务
在很多生产把环境下,tomcat的启动要随着windows的启动一起启动,这个时候就需要将tomcat添加成服务.步骤如下: 1:环境配置 配置jdk环境变量: JAVA_HOME:jdk路径 配置p ...
- sock( ) bind( ) connect( )
Linux下的socket()函数 调用头文件<sys/socket.h>中的socket函数 int socket(int af, int type, int protocol); 1) ...
- mysql查询时特殊字符转译
commons.lang String value = StringEscapeUtils.escapeSql(searchRequest.getSearchValue());
- Delphi DbgridEh实现鼠标拖动选中列,并使复选框选中
1.先设置表格列的属性 procedure TForm_TaskToDW.InitGrid;var MyCol: TColumnEh;begin with DBGridEh_Task do be ...
- golang 导出CSV文件中文乱码的问题
golang 导出CSV文件中文乱码的问题 解决办法: 在csv文件的开头写入 UTF-8 BOM // 创建文件 dstf, err := os.Create("./data/" ...
- C 语言的运算符
算术运算 C 语言支持 + - * / % 五种运算,加减乘除取模. 所有 CPU 都内建加法器,可以完成加法操作.减法操作可以转为加法操作.大部分 CPU 都没有内置乘法器,此时编译器会把 * / ...
- $destroy——angular
参考资料:[http://odetocode.com/blogs/scott/archive/2013/07/16/angularjs-listening-for-destroy.aspx]
- django连接数据库的类型
字段类型 django的models里面字段类型除了上面的常用的 models.CharField和models.IntegerField,还有更多的类型 1.models.AutoField 自增列 ...
- 解析jmeter阶梯加压与请求的计算
用百度做例子 我们设置阶梯加压线程组的请求参数,如下图 上图表示 1:每隔2秒钟,会在1秒内启动5个线程 2:每次线程加载之后都会运行2s然后开始下一次线程加载 3:最终会加载50个线程并持续运行30 ...