更新时间:2021-08-12 12:14:12 来源:极悦 浏览800次
定义可以在编译时计算的表达式。
此类表达式可用作非类型模板参数、数组大小以及其他需要常量表达式的上下文,例如
整数n = 1 ;
std:: array < int , n > a1 ; // 错误:n 不是常量表达式
const int cn = 2 ;
std:: array < int , cn > a2 ; // OK: cn 是一个常量表达式
一个核心常量表达式是任何表达式,其评价不会评估以下情形之一:
的this指针,除了在constexpr功能正被评估作为表达式的一部分
调用未声明为constexpr的函数(或构造函数)的函数调用表达式
constexpr int n = std:: numeric_limits < int > :: max ( ) ; // OK: max() 是 constexpr
constexpr int m = std:: time ( nullptr ) ; // 错误:std::time() 不是 constexpr
对constexpr已声明但未定义的函数调用
对constexpr函数/构造函数模板实例化的函数调用,其中实例化无法满足constexpr 函数/构造函数要求。
(C++20 起)对 constexpr 虚函数的函数调用,在常量表达式中不可使用的对象上调用,并且其生命周期开始于该表达式之外。
超出实现定义限制的表达式
一个表达式,其求值会导致任何形式的核心语言未定义行为(包括有符号整数溢出、被零除、数组边界外的指针运算等)。未指定是否检测到标准库未定义行为。
constexpr 双d1 = 2.0 / 1.0 ; // OK
constexpr double d2 = 2.0 / 0.0 ; // 错误:未定义
constexpr int n = std:: numeric_limits < int > :: max ( ) + 1 ; // 错误:溢出
int x, y, z [ 30 ] ;
constexpr 自动e1 = & y - & x ; // 错误:未定义的
constexpr auto e2 = & z [ 20 ] - & z [ 3 ] ; // OK
constexpr std:: bitset < 2 > a ;
constexpr bool b = a [ 2 ] ; // UB,但未指定是否检测到
(直到 C++17)一个lambda 表达式
应用于联合或其子对象的非活动成员的左值到右值隐式转换或修改(即使它与活动成员共享公共初始序列)
(C++20 起)应用于具有不确定值的对象的左值到右值隐式转换
为其活动成员(如果有)是可变的联合调用隐式定义的复制/移动构造函数或复制/移动赋值运算符,除非联合对象的生命周期在此表达式的计算中开始
(C++17 起) (C++20 前)赋值表达式或重载赋值运算符的调用将改变联合的活动成员
引用变量或引用类型数据成员的id 表达式,除非该引用可用于常量表达式或其生命周期在此表达式的计算中开始
从简历转换 无效* 任何指向对象类型的指针
(直到 C++20)dynamic_cast
reinterpret_cast
(直到 C++20)伪析构函数调用
(C++14 前)自增或自减运算符
(C++14 起)对象的修改,除非该对象具有非易失性文字类型并且其生命周期在表达式的求值内开始
constexpr int incr ( int & n ) {
return ++ n ;
}
constexpr int g ( int k ) {
constexpr int x = incr ( k ) ; // 错误:incr(k) 不是核心常量
// 表达式,因为 k 的生命周期
// 开始于表达式 incr(k) 之外
return x ;
}
constexpr int h ( int k ) {
int x= incr ( k ) ; // OK: x 不需要用核心初始化
// 常量表达式
return x ;
}
constexpr int y = h ( 1 ) ; // OK:用值 2 初始化 y
// h(1) 是一个核心常量表达式,因为
// k 的生命周期从表达式 h(1) 内部开始
(直至C ++ 20)一个typeid施加到多态型的一个glvalue表达
一个new-expression ,除非选定的分配函数是一个可替换的全局分配函数并且分配的存储在此表达式的计算中被释放 (C++20 起)
一个delete-expression ,除非它解除分配在此 expession 的计算中分配的存储区域 (C++20 起)
(C++20 起)对std::allocator::allocate的调用,除非已分配的存储在此表达式的计算中被释放
(C++20 起)对std::allocator::deallocate的调用,除非它解除分配在此 expession 求值内分配的存储区域
(因为C ++ 20)的AWAIT表达或产量表达
(因为C ++ 20)一个三通比较时的结果是不确定的
结果未指定时的等式或关系运算符
(C++14 前)赋值或复合赋值运算符
抛出表达式
(因为C ++ 20)的ASM-声明
(因为C ++ 14)所述的调用的va_arg宏时,的调用是否的va_start宏可以评估是未指定的
(C++20 起)会抛出异常的dynamic_castortypeid表达式
在 lambda 表达式内部,this对该 lambda 外部定义的变量的引用或引用,如果该引用将是 odr 使用
void g ( ) {
const int n = 0 ;
constexpr int j = * & n ; // OK:在 lambda 表达式之外
[ = ] { constexpr int i = n ; // OK: 'n' 不是 odr 使用的,也没有在这里捕获。
constexpr int j = * & n ; // 格式错误:'&n' 将是 'n' 的 odr 使用。
} ;
}
甲常量表达式是任一
左值 (C++14 前)泛 左值(C++14起)核心常量表达式,它指的是
具有非临时静态存储持续时间的对象,或
具有静态存储持续时间的临时对象,但其值满足以下纯右值的约束,或
(C++14 起)
一个非即时 (因为C ++ 20)功能
一个纯右值核心常量表达式,其值满足以下约束:
如果该值是类类型的对象,引用类型的每个非静态数据成员是指实体满足用于约束的左值 (直到C ++ 14) glvalues (因为C ++ 14)以上
如果值是指针类型,它持有
具有静态存储期的对象的地址
超过具有静态存储持续时间的对象末尾的地址
一的地址非即时 (因为C ++ 20)功能
空指针值
如果值是指向成员函数的指针类型,则不指定立即函数
(C++20 起)
如果值是类或数组类型的对象,则每个子对象都满足这些值的约束
积分常数表达式
整型常量表达式是隐式转换为纯右值的整型或无作用域枚举类型的表达式,其中转换后的表达式为核心常量表达式。如果在需要整型常量表达式的地方使用类类型的表达式,则该表达式会在上下文中隐式转换为整型或无作用域枚举类型。
以下上下文需要整数常量表达式:
数组边界
new 表达式中除第一个以外的 维度
(直到 C++14)
位域长度
基础类型不固定时的枚举初始值设定项
对齐方式。
转换后的常量表达式
甲转换常量表达式类型T是一个表达式隐式转换为类型T,其中,所述转换后的表达式是一个常量表达式,并且隐式转换序列只包含:
constexpr 用户定义的转换(因此可以在需要整数类型的地方使用类)
左值到右值的转换
积分促销
非缩小积分转换
以下表达式或转换可能是常量评估:
明显的常量评估表达式
潜在评估表达式
花括号初始化器列表的直接子表达式(可能需要不断评估以确定转换是否正在缩小)
address-of (unary &) 出现在模板化实体中的表达式(可能需要不断求值来确定这样的表达式是否依赖于值)
上述之一的子表达式不是嵌套未计算操作数的子表达式
如果函数是constexpr 函数并由可能是常量求值的表达式命名,则需要该函数进行常量求值。
如果变量是constexpr 变量,或者是非易失性 const 限定的整数类型或引用类型,并且表示它可能是常量评估的id 表达式,则需要一个变量来进行常量评估。
一个默认的功能和实例化的定义函数模板专业化或可变模板专业化 (因为C ++ 14)如果该功能被触发的或可变的 (因为C ++ 14)需要用于恒定评估。
以上就是极悦小编介绍的"常量表达式详解",希望对大家有帮助,想了解更多可查看Java极悦在线学习。极悦在线学习教程,针对没有任何Java基础的读者学习,让你从入门到精通,主要介绍了一些Java基础的核心知识,让同学们更好更方便的学习和了解Java编程,感兴趣的同学可以关注一下。
0基础 0学费 15天面授
有基础 直达就业
业余时间 高薪转行
工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习