C++关键字constexpr和consteval的注意事项及说明

 更新时间:2026年05月23日 10:21:12   作者:ComputerInBook  
这篇文章主要介绍了C++关键字constexpr和consteval的注意事项及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

C++ 支持两种不可变性概念(即状态不可变的对象)

const

  • 其大致含义是“我承诺不会更改此值”。
  • 它主要用于定义接口,以便在通过指针和引用将数据传递给函数时,无需担心数据会被修改。
  • 编译器会强制执行由 const 所作的这一承诺。const 变量的值可以在运行时计算得出。

constexpr

  • 其大致含义是“在编译时进行求值”
  • 它主要用于定义常量,以便将数据存放在只读内存中(从而降低数据被破坏的风险),同时也旨在提升性能。constexpr 变量的值必须由编译器在编译时计算得出。

例如:

	constexpr int dmv = 17; // dmv 是一个命名常量
	int var = 17; // var 不是一个常量
	const double sqv = sqrt(var); // sqv 是一个命名常量,可能在运行时计算
	double sum(const vector<double>&); // sum 不会修改其参数值
	vector<double> v{ 1.2, 3.4, 4.5 }; // v 不是一个常量
	const double s1 = sum(v); // 可行: sum(v) 在运行时计算
	constexpr double s2 = sum(v); // 错误: sum(v) 不是一个常量表达式

若要使函数可在常量表达式中使用(即在由编译器进行求值的表达式中),该函数必须定义为 constexpr 或 consteval

例如:

constexpr double square(double x) { return x*x; }
constexpr double max1 = 1.4*square(17); // 可行: 1.4*square(17) 是一个常量表达式,编译时计算
constexpr double max2 = 1.4*square(var); // 错误: var 不是一个常量, 因此square(var) 不是一个常量,无法在编译时进行计算
const double max3 = 1.4*square(var); // 可行: 可以在运行时计算

constexpr 函数可以接受非常量实参,但在这种情况下,其求值结果将不再是常量表达式。我们允许在不强制要求常量表达式的语境中,调用带有非常量表达式实参的 constexpr 函数。这样一来,我们便无需重复定义本质上完全相同的函数——即无需分别为常量表达式和变量各定义一个版本。若我们希望某个函数仅用于编译期求值,则应将其声明为 consteval而非 constexpr。例如:

consteval double square2(double x) { return x*x; }
constexpr double max1 = 1.4*square2(17); // 可行: 1.4*square(17) 是一个常量表达式
const double max3 = 1.4*square2(var); // 错误: var 的定义不是一个常量而是变量

声明为 constexpr  或  consteval 的函数,是 C++ 对“纯函数(pure functions)”这一概念的实现。它们不得产生副作用,且只能通过参数传递给它们的信息。

具体而言,它们不能修改非局部变量,但允许包含循环结构并使用自身的局部变量。

例如:

constexpr double nth(double x, int n) // 假设 0<=n
{
double res = 1;
int i = 0;
while (i<n) { // while循环: 条件为真则执行
res *= x;
++i;
}
return res;
}

在某些语境下,语言规则强制要求使用常量表达式(例如:数组边界 (§1.7)、case 标签 (§1.8)、模板值实参 (§7.2),以及使用 constexpr  声明的常量)。而在其他情况下,编译期求值对于提升性能至关重要。即便暂不考虑性能因素,不可变性(即对象处于一种不可更改的状态)这一概念本身也是一个重要的设计考量。

注意:

consteval 是 C++20 新增的一个关键字,其旨在强制函数编译时求值(即将函数声明为一个“即时”函数),且只能用于函数或函数模板,其调用参数必须是常量,不能是变量,是对 constexpr  的进一步限制

 例如:

consteval int sqr(int n)
{
	return n * n;  //调用时参数必须是常量
}
constexpr int r = sqr(100); // 可行:编译时计算,参数是常量

int x = 100;
int r2 = sqr(x);            // 错误: 调用不会产生一个常量,参数是变量

const int x = 100;        //可行:参数是常量
int r2 = sqr(x);
constexpr int r3 = sqr(x);
const int r4 = sqr(x);    

consteval int sqrsqr(int n)
{
	return sqr(sqr(n));     // 这时不是一个常量表达式, 但可行,因为调用者是 consteval 函数
}

constexpr int dblsqr(int n)
{
	return 2 * sqr(n);      // 错误: 其外围函数不是一个 consteval
	// 且 sqr(n) 不是一常量,无法在编译时进行计算
}

consteval int f() { return 42; } //可行
consteval auto g() { return &f; }
consteval int h(int (*p)() = g()) { return p(); }
constexpr int r = h();  // 可行
constexpr auto e = g(); // 格式错误:一个立即函数指针不允许作为一个常量表达式结果

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 详解C/C++中const关键字的用法及其与宏常量的比较

    详解C/C++中const关键字的用法及其与宏常量的比较

    简单的说const关键字修饰的变量具有常属性,也就是说它所修饰的变量不能被修改,下文给大家介绍C/C++中const关键字的用法及其与宏常量的比较,需要的朋友可以参考下
    2017-07-07
  • C中qsort快速排序使用实例

    C中qsort快速排序使用实例

    在学习C++ STL的sort函数,发现C中也存在一个qsort快速排序,要好好学习下C的库函数啊
    2014-01-01
  • VC小技巧汇总之对话框技巧

    VC小技巧汇总之对话框技巧

    这篇文章主要介绍了VC小技巧汇总之对话框技巧,非常实用!对于进行VC开发有一定的参考借鉴价值,需要的朋友可以参考下
    2014-07-07
  • C++ 命名空间避免命名冲突的实现

    C++ 命名空间避免命名冲突的实现

    命名空间是C++中用来避免命名冲突的一种机制,本文主要介绍了C++ 命名空间避免命名冲突的实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • C语言实现K-Means算法

    C语言实现K-Means算法

    这篇文章主要为大家详细介绍了C语言实现K-Means算法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • Python HTTP服务搭建显示本地文件

    Python HTTP服务搭建显示本地文件

    这篇文章主要介绍了Python HTTP服务搭建显示本地文件的相关资料,需要的朋友可以参考下
    2017-02-02
  • C++中的const和constexpr详解

    C++中的const和constexpr详解

    C++ const 和 constexpr 的区别呢,constexpr表示这玩意儿在编译期就可以算出来(前提是为了算出它所依赖的东西也是在编译期可以算出来的)。而const只保证了运行时不直接被修改(但这个东西仍然可能是个动态变量)。下面我们来详细讲解下。
    2016-01-01
  • C++多线程实现绑定CPU的方法详解

    C++多线程实现绑定CPU的方法详解

    这篇文章主要为大家详细介绍了C++如何利用多线程实现绑定CPU,文中的示例代码简洁易懂,具有一定的学习价值,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-05-05
  • C/C++宽窄字符转换与输出的多种实现方法

    C/C++宽窄字符转换与输出的多种实现方法

    本文主要介绍了C/C++宽窄字符转换与输出的多种实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • 浅析C语言调试器GDB和LLDB的使用方法

    浅析C语言调试器GDB和LLDB的使用方法

    这篇文章主要介绍了C语言调试器GDB和LLDB的使用方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-12-12

最新评论