C++ constexpr 关键字

constexpr 是在 C++11 中引入的关键字。它的作用就是实现在编译时对表达式求解,运行时直接使用结果,避免一些计算,从而提高程序的效率。该关键字可以用于声明常量、函数、对象、和模板参数。

1. constexpr 常量

常量是指在程序运行过程中其值不会发生变化的量,比如数学中的圆周率 π,物理中的光速,以及程序中需要多次使用的固定参数。

常量分为:

  • 编译期常量
    • 值在编译时确定:编译期常量的值必须在编译时就能确定,运行时不能修改。
    • 不占运行时内存:编译器会将常量值直接插入到使用它的地方,因此在运行时不占用额外的内存。
    • 优化:编译器可以对编译期常量进行优化,减少不必要的计算和存储。
  • 运行期常量:
    • 值在运行时确定:运行期常量的值只能在程序运行时确定,运行时不能修改。
    • 占用运行时内存:因为编译器在编译时无法确定其值,所以需要在运行时为其分配内存。
    • 优化:编译器一般无法对运行期常量进行优化。

在 C++ 中定义一个常量可以使用两个关键字:constconstexpr,两者的区别:

  • const 可以定义编译期常量,也可以定义运行期常量
  • constexpr 只能用于定义编译期的常量
#if 1

#include <iostream>
using namespace std;


// 1. const
void test01()
{
	// 编译期常量
	const int a = 10;
	/*
		int ret1 = a + a;
		00007FF625B21EE2  mov         dword ptr [ret1],14h
	*/
	int ret1 = a + a;


	// 运行期常量
	int temp = 20;
	const int b = temp;
	/*
		int ret2 = b + b;
		00007FF76AA01EF6  mov         eax,dword ptr [b]
		00007FF76AA01EF9  mov         ecx,dword ptr [b]
		00007FF76AA01EFC  add         ecx,eax
		00007FF76AA01EFE  mov         eax,ecx
		00007FF76AA01F00  mov         dword ptr [ret2],eax
	*/
	int ret2 = b + b;
}


// 2. constexpr
void test02()
{
	// 编译期常量
	constexpr int a = 10;
	/*
		int ret = a + a;
		00007FF7AEA71EE2  mov         dword ptr [ret],14h
	*/
	int ret = a + a;


	int temp = 20;
	// 报错:表达式的计算结果不是常数
	// constexpr int b = temp;
}


int main()
{
	test01();
	test02();

	return 0;
}

#endif

2. constexpr 函数

普通函数需要在运行时执行以获得计算结果,而 constexpr 函数则允许在编译时执函数计算结果,这可以将一些计算由运行时转移到编译时,从而提高程序运行时的性能。

#if 1

#include <iostream>
using namespace std;


constexpr int calculate(int a, int b, char m)
{
	// 条件语句
	if (0 == a && 0 == b)
	{
		return 0;
	}

	// 局部变量
	int temp1 = 0;
	int temp2 = 0;

	// 循环语句
	for (int i = 0; i < a; ++i)
	{
		temp1 += i;
	}

	for (int i = 0; i < b; ++i)
	{
		temp2 += i;
	}

	// 条件语句
	int result = 0;
	switch (m)
	{
		case '+':
			result = temp1 + temp2;
			break;
		case '-':
			result = temp1 - temp2;
			break;
		case '*':
			result = temp1 * temp2;
			break;
		case '/':
			result = temp1 / temp2;
			break;
		default:
			break;
	}

	return result;
}


void test()
{
	constexpr int a = 10;
	constexpr int b = 20;
	constexpr char m = '+';
	/*
		注意点:
		1. 函数的参数必须是编译期常量
		2. 函数的返回值必须使用 constexpr 变量承接
	*/

	// 1. 编译期计算
	/*
		constexpr int ret1 = calculate(a, b, m);
		00007FF628F918FD  mov         dword ptr [ret1],0EBh  
	*/
	constexpr int ret1 = calculate(a, b, m);

	// 2. 运行期计算
	/*
		int ret2 = calculate(a, b, m);
		00007FF78B3D1904  mov         r8b,2Bh  
		00007FF78B3D1907  mov         edx,14h  
		00007FF78B3D190C  mov         ecx,0Ah  
		00007FF78B3D1911  call        calculate (07FF78B3D13DEh)  
		00007FF78B3D1916  mov         dword ptr [ret2],eax 
	*/
	int ret2 = calculate(a, b, m);
}



int main()
{
	test();
	return 0;
}

#endif

3. constexpr 对象

constexpr 对象是使用 constexpr 关键字声明的对象,其值在编译时就已经确定,并且可以用于在编译时执行某些操作。与常量表达式相比,constexpr 对象更加灵活,因为它们不仅可以在编译时用于确定常量表达式的值,还可以在运行时用于一般的计算和操作。

#if 1

#include <iostream>
using namespace std;


class MyObject 
{
public:
	// 1. 构造函数必须使用初始化列表
	constexpr MyObject(int a, int b, int c) : m_a(a), m_b(b), m_c(c){}


	// 2. 常函数(编译器、运行期调用)
	constexpr int const_sum() const
	{
		return m_a + m_b + m_c;
	}

	// 3. 普通函数(运行时调用)
	int common_sum()
	{
		return m_a + m_b + m_c;
	}

private:
	int m_a;
	int m_b;
	int m_c;
};


void test()
{
	// 常对象
	constexpr MyObject o1(10, 20, 30);
	/*
		constexpr int r1 = o1.const_sum();
		00007FF6BC641AB2  mov         dword ptr [ret1],3Ch  
	*/
	constexpr int r1 = o1.const_sum();
	cout << r1 << endl;

	// 不能修改的常对象
	const MyObject o2(10, 10, 10);
	/*
		int r2 = o2.const_sum();
		00007FF7CCD02515  lea         rcx,[o2]  
		00007FF7CCD02519  call        MyObject::const_sum (07FF7CCD01271h)  
		00007FF7CCD0251E  mov         dword ptr [r2],eax  
	*/
	int r2 = o2.const_sum();
	cout << r2 << endl;


	// 普通对象
	MyObject o3(10, 20, 30);
	/*
		int ret2 = obj2.const_sum();
		00007FF7A0491AF5  lea         rcx,[obj2]  
		00007FF7A0491AF9  call        MyObject::const_sum (07FF7A049121Ch)  
		00007FF7A0491AFE  mov         dword ptr [ret2],eax  
		
		int ret3 = obj2.common_sum();
		00007FF7A0491B04  lea         rcx,[obj2]  
		00007FF7A0491B08  call        MyObject::common_sum (07FF7A0491181h)  
		00007FF7A0491B0D  mov         dword ptr [ret3],eax  
	*/
	int r3 = o3.const_sum();
	int r4 = o3.common_sum();
	cout << r3 << " " << r4 << endl;	
}


int main()
{
	test();
	return 0;
}

#endif

至此,关于 constexpt 讲解完毕,希望对你有所帮助!

未经允许不得转载:一亩三分地 » C++ constexpr 关键字
评论 (0)

2 + 8 =