《随笔十六》—— C++中的 “ constexpr 函数、constexpr 构造函数、字面值常量类 ——C++11 ”

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/84673824

目录

constexpr 函数 (C++11)

constexpr 构造函数 (C++11)constexpr 构造函数



constexpr 函数 (C++11)


● constexpr 函数 是 指用于常量表达式的函数。 不过要注意的是:

函数的返回类型及所有形参的类型都得是字面值类型。(一般来说基本的数据类型、引用和指针都属于字面值类型,自定义的类、string 不属于字面值,不可以定义为constexpr。)

而且函数体中必须有且只有一条return语句。

constexpr int new_sz()
{
	return 42+10;
}
int main()
{
 
	constexpr auto foo = new_sz(); //正确:foo 是一个常量表达式
 
	cout << foo << endl;
	system("pause");
	return EXIT_SUCCESS;
}

● 说明 : 因为编译器能在程序编译时验证 new_sz() 函数返回的是常量表达式, 所以可以用 new_sz 函数 初始化 constexpr 类型的变量 foo

因执行该初始化任务时, 编译器把对 constexpr 函数的调用替换成其结果值。为了能在编译过程中随时展开, constexpr 函数被隐式地指定为内联函数。

● 注意 : constexpr 函数体内也可以包含其他语句, 只要这些语句在运行时不执行任何操作就行。 例如: constexpr 函数中可以有 空语句、类型别名 以及 using 声明.

● 注意 : 我们允许constexpr 函数的返回值并非一个常量。 constexpr 函数不一定返回常量表达式
 

constexpr int new_sz()
{
    return 42;
}
constexpr size_t scale(size_t cnt)
{
    return new_sz()*cnt;
}
int main()
{
    constexpr int foo = new_sz();
 
    int arr[scale(2)] = {};  //正确: scale(2) 是常量表达式
 
     int i = 2;  //i不是常量表达式
    int a2[scale(i)];   // 错误:  scale(i) 不是常量表达式
    system("pause");
    return 0; 
}

● 和 其他函数不一样, 内联函数和constexpr 函数可以在程序中多次定义。 毕竟, 编译器要想展开函数仅有函数声明是不够的, 还需要函数的定义。

不过,对于某个给定的内联函数或者constexpr 函数来说, 它的多个定义必须完全一致。

基于这个原因, 内联函数和 constexpr 函数通常定义在头文件中。
 


constexpr 构造函数 (C++11)


前面说过,constexpr 函数的返回类型及所有形参的类型都得是字面值类型。(一般来说基本的数据类型、引用和指针都属于字面值类型,自定义的类、string 不属于字面值,不可以定义为constexpr。) 不过这里有个特殊情况是,  某些自定义的类也是 字面值类型的。和其它类不同的 是, 字面值类型的类可能含有 constexpr 成员函数。  这样的成员 必须符合 constexpr 函数的所有要求, 它们是隐式的const。

数据成员都是字面值类型的聚合类是字面值常量类。如果一个类不是聚合类,但它符合下述要求,则它也是一个字面值常量类:

数据成员都必须是字面值类型。

类必须至少含有一个constexpr构造函数。

如果一个数据成员含有类内初始值,则内置类型成员的初始值必须是一条常量表达式;或者如果成员属于某种类类型,则初始值必须使用成员自己的constexpr构造函数。

类必须使用析构函数的默认定义, 该成员负责销毁类的对象(参见7.1.5节,第239页)。


constexpr 构造函数


尽管构造函数不能是const的( 参见7.1.4节,第235页), 但是字面值常量类的构造函数可以是constexpr (参见6.5.2节,第213页)函数。事实上,一个字面值常量类必须至少提供一个constexpr构造函数。

constexpr构造函数可以声明成 = default (参见7.1.4节,第237页)的形式(或者是删除函数的形式,我们将在13.1.6节(第449页)介绍相关知识)。

否则, constexpr沟造函数就必须既符合构造函数的要求(意味着不能包含返回语句), 又符合constexpr函数的要求 (意味着它能拥有的唯一可执行语句就是返回语句(参见6.5.2节,第214页))。综合这两点可知, constexpr构造函数体一般来说应该是空的。我们通过前置关键字 constexpr就可以声明一个constexpr构造函数了:

class Debug
{
public:
	constexpr Debug(bool b = true) :hw(b), io(b), other(b) {}
	constexpr Debug(bool h, bool i, bool o) : hw(h), io(i), other(o) {}
	constexpr  bool any() const //注意记得在尾部加上const,不然编译错误
	{
		return(hw || io || other);
	}
	void set_io(bool b)
	{
		io = b;
	}
	void set_hw(bool b)
	{
		hw = b;
	}
	void set_other(bool b)
	{
		other = b;
	}
private:
	bool hw;
	bool io;
	bool other;
};

int main()
{
    // constexpr构造函数用于生成constexpr对象以及constexpr函数的参数或返回类型

	constexpr Debug io_sub(false, true, false);

	if (io_sub.any())
	{
		//一些语句
	}

	constexpr Debug prod(false);
	if (prod.any())
	{
		//一些语句
	}
	system("pause");
	return  0;

}

constexpr构造函数必须初始化所有数据成员初始值, constexpr构造函数中或者是一条常量表达式。

猜你喜欢

转载自blog.csdn.net/qq_34536551/article/details/84673824