c++ constexpr构造函数有什么作用
给构筑bai函数加上constexpr之后, 这个构筑函数就只能du用初始化列表给属性赋值而函zhi数体要是空dao的, 之后这个构造函数就可以被用在其它constexpr里
constexpr表示一个函数或者表达式可以在编译时就求出值, 可以用作常量, 用constexpr构造函数创建的对象也是如此可以当作常量使用
c++中的构造函数..前加上explicit有什么用??
C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。
C++中, 一个参数的构造函数, 承担了两个角色。 1 是个构造器 2 是个默认且隐含的类型转换操作符。
所以, 有时候在我们写下如 AAA = XXX, 这样的代码, 且恰好XXX的类型正好是AAA单参数构造器的参数类型, 这时候编译器就自动调用这个构造器, 创建一个AAA的对象。
这样看起来好象很酷, 很方便。 但在某些情况下(见下面权威的例子), 却违背了我们(程序员)的本意。 真是成也萧何, 败也萧何。 这时候就要在这个构造器前面加上explicit修饰, 指定这个构造器只能被明确的调用,使用, 不能作为类型转换操作符被隐含的使用。 呵呵, 看来还是光明正大些比较好。
explicit构造函数的作用
解析:
explicit构造函数是用来防止隐式转换的。请看下面的代码:
1 class Test1
2 {
3 public:
4 Test1(int n) { num = n; } //普通构造函数
5 private:
6 int num;
7 };
8
9 class Test2
10 {
11 public:
12 explicit Test2(int n) { num = n; } //explicit(显式)构造函数
13 private:
14 int num;
15 };
16
17 int main()
18 {
19 Test1 t1 = 12; //隐式调用其构造函数, 成功
20 Test2 t2 = 12; //编译错误,不能隐式调用其构造函数
21 Test2 t3(12); //显示调用成功
22 return 0;
23 }
Test1的构造函数带一个int型的参数,代码19行会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此代码20行会出现编译错误。
普通构造函数能够被隐式调用。而explicit构造函数只能被显示调用。
测试一下这段代码,然后把T的构造函数前面加上explicit再测一下看会有什么错误?
class T
{
public:
T(int _n): n(_n){}
int geti()const{return n;}
private:
int n;
};
void fun(T &t)
{
cout<<t.geti()<<endl;
}
int main()
{
fun(100);
return 0;
}
=============================================================
constexpr和const数组的区别
const是表bai明这个值是constant的,但是不必在编译du期确定,然而数zhi组的大小是需要在编译期确定的dao,如:
int i; // not constant
const int size = i; // fine!
int arr[size]; // Error!
然而对于constexpr,则表明这个值不仅是constant的,而且也是编译期确定的
int i; // not constant
constexpr int size = i; // Error!
于是,constexpr修饰的是可以用于数组大小的。
而为什么在main的const是可以的呢?其实这跟const无关,而是使用了C99的一个特性,名叫variable length array(简称VLA),所以即使是这样:
int main()
{
int i;
cin >> i;
int arr[i];
}
你使用你现在的GCC编译,也是可以通过的
那么,为什么VLA的数组不能在全局区呢?那么我想从两方面来解释:
1. 标准文档
在C11标准文档的 6.7.6.2 Array declarators
2.
If an identifier is declared as having a variably modified type, it
shall be an ordinary identifier (as defined in 6.2.3), have no linkage,
and have either block scope or function prototype scope. If an
identifier is declared to be an object with static or thread storage
duration, it shall not have a variable length array type.
10. All declarations of variably modified (VM) types have to be at either block scope or
function prototype scope. Array objects declared with the _Thread_local, static, or extern
storage-class specifier cannot have a variable length array (VLA) type.
However, an object declared with the static storage-class specifier can
have a VM type (that is, a pointer to a VLA type). Finally, all
identifiers declared with a VM type have to be ordinary identifiers and
cannot, therefore, be members of structures or unions.
2. 原理解释
GCC实现VLA的方式,是allocate memory在stack上,所以,隐藏在VLA下面的是也发生了Memory Allocation的动作,所以你怎么能在全局区去进行Memory Allocation呢?
最
后,再补充一些constexpr的东西。这是一个C++11引入的东西,C++14对constexpr的范围进行了更大程度的条件放松,而这里我就仅
谈C++11的。刚才谈到了constexpr是限定了修饰的为编译期间可确定的常量,但是constexpr也是可以用于函数的,而这个时候就不一定可
以保证最后的值是constexpr了,那么我那次开C++11讲座的时候,介绍的一个小技巧,就是用数组检测是不是编译期的常量,这也是利用了数组大小
需要编译期间确定的特点:
constexpr int sz()
{
return 47;
};
constexpr size_t scale(size_t cnt)
{
return sz() * cnt;
}
const int i = 3;
int arr[scale(i)]; // OK
int j = 3;
int arr[scale(j)]; //Error!
===================================================
C++ 11 新特性: constexpr变量和constexpr函数
freshman94 2019-04-16 17:07:46 2010 收藏 1
分类专栏: C++
版权
constexpr变量
字面值类型包括算术类型、引用、指针、枚举和数据成员都是字面值类型的聚合类。
聚合类的定义:
所有成员都是public的。
没有定义任何构造函数。
没有类内初始值。
没有基类,也没有虚函数。
如:
struct Data {
int ival;
string str;
};
如果一个类不是聚合类,但它符合下述要求,则它也是一个字面值常量类:
数据成员必须是字面值类型
类必须有一个constexpr构造函数
如果一个数据成员含有类内初始值,则内置类型成员的初始值必须是一条常量表达式(其定义见下文);或者如果成员属于某种类类型,则初始值必须使用成员自己的constexpr构造函数
类必须使用构造函数的默认定义
常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。
const int max_files=20; // max_files是常量表达式
const int limit=max_files+1; //limit是常量表达式
int staff_size =27; // staff_size不是常量表达式
const int sz=get_size(); // sz不是常量表达式
尽管staff_size的初始始是个字面值常量,但由于它的数据类型非const,所以它不是常量表达式。尽管sz本身是一个常量,但它的具体值直到运行时才能得到,也不是常量表达式。
在一个复杂的系统中,很难分辨一个初始值到底是不是常量表达式。当然可以定义一个const变量并把它的初始值设为我们认为的某个常量表达式,但在实际使用中,尽管要求如此却常常发现初始值并非常量表达式的情况。
C++11规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
constexpr int mf=20; //20是常量表达式
constexper int limit=mf+1; //mf+1是常量表达式
constxper int sz=size(); //只有当size是一个constxper函数时才是一条正确的声明语句
不能用普通函数作为constexpr变量的初始值,只能用constexpr函数去初始化constexpr变量。这种函数足够简单,以使得编译时就可以计算其结果。
一般来说,如果你认定变量是一个常量表达式,那就把它声明成constexpr类型。
constexpr函数
constexpr函数是指能用于常量表达式的函数。该函数要遵循几项约定:函数的返回类型及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条return语句:
constexpr int new_sz() { return 42; }
constexpr int foo = new_sz();
在对变量foo初始化时,编译器把对constexpr函数的调用替换成其结果值。为了能在编译过程中随时展开,constexpr函数被隐式地指定为内联函数。
constexpr函数体内也可以包含其它语句,只要这些语句在运行时不执行任何操作就行。例如,constexpr函数中可以有空语句、类型别名以及using声明。
需要注意的是,我们允许constexpr函数的返回值并非一个常量:
//如果arg是常量表达式,则scale(arg)也是常量表达式
constexpr size_t scale(size_t cnt){ return new_sz() * cnt; }
当scale的实参是常量表达式时,它的表达式也是常量表达式,反之则不然:
int arr[scale(2)]; //正确:scale(2)是常量表达式
int i = 2; //i不是常量表达式
int a2[scale(i)]; //错误:scale(i)不是常量表达式
当把scale函数用在需要常量表达式的上下文中时,如果其结果恰好不是常量表达式,编译器将发出错误信息。
注意,我们要把内联函数和constexpr函数定义在头文件中。因为内链函数是内部链接的,如果你在b.cpp中定义这个函数,那么在a.cpp中即使有这个函数声明,但由于内联函数是内部链接的,所以b.cpp不会提供其定义。所以在链接时a.obj无法找到这个函数的定义,便会出现无法解析的外部符号的错误
constexpr构造函数
我们知道,构造函数不能是const的。因为当我们创建一个类的const对象时,直到构造函数完成初始化过程,对象才能真正取得其”常量“属性。因此,构造函数在const对象的构造过程中可以可以向其写值。但是字面值常量类的构造函数可以是constexpr函数。事件上,一个字面值常量类必须至少提供一个constexpr函数。
constexpr构造函数可以声明成=default的形式(或者是删除函数的形式)。否则,constexpr构造函数体一般来说应该是空的,因为构造函数不能包含返回语句,而constexpr函数的唯一可执行语句就是返回语句。constexpr构造函数的声明形式如下:
class Debug {
public:
constexpr Debug(int i) :i_(i) {}
private:
int i_;
};
constexpr构造函数必须初始化所有数据成员,初始值或者使用constexpr构造函数,或者是一条常量表达式。
————————————————
版权声明:本文为CSDN博主「freshman94」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_22660775/article/details/89336997
==========================================================================================
https://www.cnblogs.com/thomas76/p/8646036.html
https://www.cnblogs.com/jesse123/p/6209938.html
http://www.cplusplus.com/reference/type_traits/is_literal_type/
https://recomm.cnblogs.com/blogpost/8646036
https://stackoverflow.com/questions/56469764/literal-class-type-member-function-constraints
https://www.kdab.com/kdab-contributions-to-qt-5-0-part-4/
https://stackoverflow.com/questions/14307996/when-should-literal-classes-be-used-in-c
http://www.itkeyword.com/doc/0179911580408415989/c++11
http://www.itkeyword.com/doc/3659751867155628x408/raii-c++11
http://www.itkeyword.com/doc/5127476683758632308/c++11
http://www.itkeyword.com/doc/1075613094017327x865/c++11-range-based-for-loops
https://blog.csdn.net/craftsman1970/article/details/81087262
https://blog.csdn.net/qq_41017648/article/details/90044087
https://blog.csdn.net/craftsman1970/article/details/80208893
https://blog.csdn.net/craftsman1970/article/details/80244873