C++常量表达式函数

目录

常量表达式的功能

constexpr关键字和用户定义型别 

constexpr对象

constexpr函数 

constexpr模版


整数字面值即为常量表达式(constant expression),简单的算术表达式也是常量表达式,如20*4+8。整型常量自身可依照常量表达式进行初始化,还能利用前者组成新的常量表达式:

const int x = 2;
const int three_x = 3 * 2;
const int y = 6;
const int y3x = y + three_x;

常量表达式的功能

一些功能只能靠常量表达式实现:

1.设定数组界限:

int bounds = 99;
int array[bounds];		//错误
const int bounds2 = 4;
int array2[bounds2];	//正确

2.设定非类型模版参数(nontype template parameter):

template<unsigned size>
struct test
{};
test<bounds> ia;	//错误,界限bounds不是常量表达式
test<bounds2> ia2;	//正确,界限bounds是常量表达式

3.充当静态常量整型数据成员的初始化表达式:

class X
{
	static const int the_answer = y3x;
};

4.对于能够进行静态初始化的内建型别和聚合体,可以将常量表达式作为其初始化表达式:

struct aggregrate
{
	int a;
	int b;
};
static aggregrate ma1 = { y3x , 245 };	//静态初始化,避免初始化先后次序问题,从而避免条件竞争
int dd = 256;
static aggregrate ma2 = { dd, dd };		//动态初始化

5.constexpr关键字的主要功能是充当函数限定符,声明为constexpr的函数可以在常量表达式中使用

constexpr int square(int x)
{
	return x * x;
}

int array[square(6)];

使用constexpr函数充当常量表达式要求其参数也为常量表达式,否则视为普通函数的调用,因此不能用来设定数组界限:

int dd = 20;
int array[square(dd)]; //错误,dd不是常量表达式

constexpr关键字和用户定义型别 

除了上述例子所用的内建型别,只要满足要求并可充当字面值(代码中明确写出的值)的类型,就允许成为常量表达式,其必须满足的条件如下(关键字【平实】):

·必须具有平实拷贝构造函数

·必须具有平实析构函数

·非静态数据成员和基类都属于平实型别

·必须具备平实默认构造函数或常量表达式构造函数(后者不能进行拷贝/移动构造)

我们基于以下例子讨论:

class CX
{
private:
	int a;
	int b;
public:
	CX() = default;
	CX(int a_, int b_):a(a_),b(b_){}
	int get_a()const
	{
		return a;
	}
	int get_b() const
	{
		return b;
	}
	int foo()const
	{
		return a + b;
	}
};

上述例子问了保留默认构造函数,显式声明为默认,该型别符合字面型别的要求,能在常量表达式中使用,我们可以给出一些constexpr函数,负责创建该类型的新实例:

constexpr CX create_cx()
{
	return CX();
}
//用于复制参数
constexpr CX clone(CX val)
{
	return val;
}

C++14放宽了限制,只要不在constexpr函数内部改动非局部变量,就几乎可以进行任意操作,可以为成员函数和构造函数加上constexpr

class CX
{
private:
	int a;
	int b;
public:
	CX() = default;
	constexpr CX(int a_, int b_):a(a_),b(b_){}
	constexpr int get_a()const
	{
		return a;
	}
	constexpr int get_b() const
	{
		return b;
	}
	constexpr int combine()const
	{
		return a + b;
	}
};

在C++11中,成员函数的const声明成了多余的修饰,因其限定作用为constexpr所包含,而C++14对该功能进行了扩充:

constexpr CX make_cx(int a)
{
	return CX(a, 1);
}
constexpr CX half_double(CX old)
{
	return CX(old.get_a()/2, old.get_b()*2);
}
constexpr int combine_squared(CX val)
{
	return square(val.combine());
}
int array[combine_squared(half_double(make_cx(10)))];

上述例子意在说明,如果需要使用复杂的方式求得某些数组界限或整型常量,凭借constexpr完成任务将省去大量运算,常量表达式和constexpr函数带来的主要好处是:若依照常量表达式初始化字面值型别对象,会发生静态初始化,从而避免条件竞争和次序问题:

CX s = half_double(CX(11, 12));

若构造函数为constexpr函数,且参数为常量表达式,所属类会进行常量初始化(即constant initialization,常量往往在编译期就完成计算,在运行期直接套用算好的值,即静态初始化阶段),在并发编程中避免条件竞争。

constexpr对象

constexpr关键字还可以用在对象上,它会将对象声明为const常量。
主要用于分析和诊断:查验对象的初始化行为,核实其所依照的初值是常量表达式、constexpr构造函数,或由常量表达式构成的聚合体初始化表达式。

constexpr int i = 45;
constexpr std::string s("Hello");	//错误,std::string不是字面值型别
int foo();
constexpr int j = foo();			//错误,foo()并未声明为constexpr

constexpr函数 

若要将某函数声明为constexper,其必须满足一定的条件,否则会产生编译错误:

·所有参数必须是字面值型别。

·返回值必须是字面值型别。

·函数只有一条return语句。

·return语句返回的表达式必须是常量表达式。

以上条件不难理解,因为constexpr函数必须能够嵌入到常量表达式中,而嵌入的结果仍然是常量表达式。C++14后放宽了部分要求:

·可以使用多条return语句。

·函数中创建的对象可以被修改。

·可以使用循环、条件分支和switch语句。

对于类所具有的constexpr成员函数,需要符合更多要求:

·constexpr成员不能是虚函数

·所述类必须是字面值型别

·构造函数必须初始化每一个基类

·构造函数必须初始化全体非静态数据成员

·成员初始化列表中的每个表达式都是常量表达式

·数据成员和基类调用构造函数进行初始化时,必须是constexpr构造函数。

constexpr模版

若函数模版或类模版加上constexpr修饰,而模版的某个特定的具现化中,其参数和返回值均不属于字面值型别,则constexpr关键字被忽略:

template<typename T>
constexpr T sum(T a, T b)
{
	return a + b;
}
constexpr int i = sum(6, 9); //具备constexpr特性
std::string ss = sum(std::string("hello"), std::string(" world")); //不具备constexpr特性

具现化的函数模版必须满足前文的全部要求,才能成为constexpr函数。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++11 引入了 constexpr 关键字,用于指定函数或对象是常量表达式常量表达式是在编译时就能计算出结果的表达式,它可以用于数组大小、模板参数等需要在编译时确定的地方。 constexpr 函数 constexpr 函数是指能在编译时求值的函数,它的返回值可以作为常量表达式使用。constexpr 函数的参数和返回值必须是字面类型。 例如,下面的函数就是一个 constexpr 函数: ```cpp constexpr int square(int x) { return x * x; } ``` 我们可以在编译时计算出 square(5) 的值,因此它是一个常量表达式。 constexpr 对象 constexpr 对象是指在编译时就能计算出值的对象。constexpr 对象必须被声明为 const,而且必须用常量表达式初始化。 例如,下面的语句定义了一个 constexpr 对象: ```cpp constexpr int max_num = 100; ``` 我们可以在编译时就知道 max_num 的值是 100,因此它是一个常量表达式。 constexpr 函数常量表达式的限制 constexpr 函数常量表达式有一些限制: 1. constexpr 函数必须有一个返回值,而且返回值必须是字面类型。 2. constexpr 函数函数体必须足够简单,能在编译时被求值。 3. constexpr 函数不能包含任何副作用,比如修改全局变量或调用非 constexpr 函数。 4. constexpr 函数的参数和返回值必须是字面类型。 5. constexpr 对象必须被声明为 const,而且必须用常量表达式初始化。 6. constexpr 对象的类型必须是字面类型。 总结 constexpr 关键字用于指定函数或对象是常量表达式。constexpr 函数常量表达式必须在编译时就能计算出值,它们有一些限制。constexpr 函数常量表达式可以用于数组大小、模板参数等需要在编译时确定的地方。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值