C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++关键字constexpr和consteval

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

作者:ComputerInBook

这篇文章主要介绍了C++关键字constexpr和consteval的注意事项及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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

const

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(); // 格式错误:一个立即函数指针不允许作为一个常量表达式结果

总结

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

您可能感兴趣的文章:
阅读全文