1、constexpr

1、const与constexpr:

  1. const: 承若不改变这个值,主要用于说明接口,这样在把变量传入函数时就不必担心变量会在函数内被改变了,编译器负责确认并执行const的承若。

  2. constexpr:在编译时求值,主要用来说明常量,作用是允许将数据置于只读内存中以及提升性能。

  3. 常量表达式指由编译器求值的表达式。

//使用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是变量
}

函数必须足够简单才能在编译期求值:

  1. constexpr函数必须包含一条独立的return语句。
  2. constexpr不能有循环,也不能有局部变量。
  3. 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的更多相关文章

  1. C++11特性——变量部分(using类型别名、constexpr常量表达式、auto类型推断、nullptr空指针等)

    #include <iostream> using namespace std; int main() { using cullptr = const unsigned long long ...

  2. [c++] constexpr and literal class

    稀奇古怪的新特性,菜鸟在此啄上一啄. 1. When should literal classes be used in C++?   2. int i; // not constant const ...

  3. C++之内联函数与constexpr

    inline 函数 规模小,流程直接且频繁调用 cout<<shortString(s1,s2)<<endl; = cout<<(s1.size()<s2.s ...

  4. Item 15: 只要有可能,就使用constexpr

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 如果说C++11中有什么新东西能拿"最佳困惑奖" ...

  5. c++基础 - constexpr

    const expression常量表达式,指值不会改变,并且在编译过程中就能得到计算结果的表达式. 复杂系统难以分辨一个初始值是否是常量表达式,因此提出constexptr以提示编译器,用来验证变量 ...

  6. constexpr和常量表达式

    常量表达式:值不会改变并且在编译过程就能得到计算结果的表达式. 字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式. 一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同 ...

  7. 【C++】C++中const与constexpr的比较

    先说结论相同点:const和consexpr都是用来定义常量的.不同点:const声明的常量,初始值引用的对象不一定是一个常量:constexpr声明的常量,初始值一定是常量表达式. constexp ...

  8. C++11 constexpr常量表达式

    常量表达式函数 要求: 函数体内只有单一的return返回语句 例如: constexpr int data() { const int i=1; //含有除了return以外的语句 return i ...

  9. 常量表达式和constexpr(c++11)

    常量表达式 常量表达式是指值不会改变且在编译阶段就能得到计算结果的表达式(两点要求) ; //是常量表达式 ; //是常量表达式 "; const int siz=s.size(); //不 ...

  10. c++ 11 游记 之 decltype constexpr

    title: c++ 11 游记 1 keyword :c++ 11 decltype constexpr 作者:titer1 zhangyu 出处:www.drysaltery.com 联系:130 ...

随机推荐

  1. 【spoj2774】最长公共子串

    题目描述: 给你两个字符串,求它们最长公共子串的长度,如果不存在公共子串则输出0. 样例输入: yeshowmuchiloveyoumydearmotherreallyicannotbelieveit ...

  2. Flume的断点续传解决

    根据需求,首先定义以下3大要素 采集源,即source——监控文件内容更新 :  exec  ‘tail -F file’ 下沉目标,即sink——HDFS文件系统  :  hdfs sink Sou ...

  3. 2018-2019-2 20165235《网络对抗技术》Exp7 网络欺诈防范

    2018-2019-2 20165235<网络对抗技术>Exp7 网络欺诈防范 实验目的 本实践的目标理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法 实验内容 (1)简单应 ...

  4. eigen 中四元数、欧拉角、旋转矩阵、旋转向量

    一.旋转向量 1.0 初始化旋转向量:旋转角为alpha,旋转轴为(x,y,z) Eigen::AngleAxisd rotation_vector(alpha,Vector3d(x,y,z)) 1. ...

  5. Linux编译部署vsftp服务

    部署vsftp服务   Hostname OS IP Software Vsftpsvr RHEL-5.8 10.0.0.58 yum install -y vsftpd yum install –y ...

  6. Mybaits查询返回值是List类型的

    查询返回值是list类型的 1 首先在接口中写方法 public interface EmployeeMapper { public List<Employee> getEmpsByLas ...

  7. symbol,iterator,generator

    1.symbol是在ES6中引入的一种基本数据类型,因为symbol是不重复.唯一的数据特性,symbol设计是被用来表示对象内部的私有属性的.     symbol.for与symbol.keyfo ...

  8. Delphi下利用WinIo模拟鼠标键盘详解 有参考价值

    https://blog.csdn.net/fgrass_163/article/details/6365296 Delphi下利用WinIo模拟鼠标键盘详解 2011年04月26日 21:03:00 ...

  9. RequestContextHolder获取request和response

    RequestContextHolder获取request和response 2019年03月16日 15:18:15 whp404 阅读数:21更多 个人分类: Spring   首先需要在web. ...

  10. python中的各个模块

    collection模块:python中的扩展数据模块#namedtuple: 生成可以使用名字来访问元素内容的tuple'''from collections import namedtuplePo ...