一、变量和基本类型
1、long long类型
long long类型:长整型,占8字节,可表示范围-2^63 ~ 2 ^ 63 - 1。
要使用long long 类型的整数必须标注对应的后缀:
对于有符号的long long 类型,后缀用"LL"或者"II"标识,就比如"10LL"就表示有符号超长整数10。
对于无符号的long long 类型,后缀用"ULL"或者"UII"标识,就比如"10ULL"就表示无符号超长整数10。
如果想要了解当前平台long long 类型的取值范围,可以使用如下3个宏查看:
LLONG_MIN:代表当前平台最小的 long long 类型整数
LLONG_MAX:代表当前平台最大的 long long 类型整数
ULLONG_MAX:代表当前平台上最大的 unsigned long long 类型整数(无符号超长整型的最小值为 0);
2、列表初始化
C++11全面使用{}进行初始化,这种初始化的方式成为列表初始化。
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
class Foo
{
public:
Foo(int) {};
~Foo() {};
};
int main()
{
int n0{};
int n1{ 1 };
int n2 = { 1 };
double d = double {1.2};
string s1{'a','b' ,'c' ,'d'};
string s2{ s1,2,2 };
string s3{ 0x61,'a'};
string s4{ "Hello World!"};
// new 操作符也可以初始化
int* p = new int{1};
int* pArr = new int[3]{ 123 };
// 类对象初始化
Foo a3 = { 123 };
Foo a4{ 123 };
std::cout << "Hello World!\n";
}
无论是类变量、数组、STL容器、类构造等都统一使用{}初始化。
3、nullptr常量
nullptr 是 nullptr_t 类型的右值常量,专用于初始化空类型指针。nullptr_t 是 C++11 新增加的数据类型,可称为“指针空值类型”。也就是说,nullpter 仅是该类型的一个实例对象(已经定义好,可以直接使用),如果需要我们完全定义出多个同 nullptr 完全一样的实例对象。
#include <iostream>
#include <cstddef>
using namespace std;
template<typename T>
void Func(int n)
{
cout << "int n" << endl;
}
void Func(void* p)
{
cout << "void* p" << endl;
}
int main()
{
// nullptr 可以被隐式转换成任意的指针类型
int* a1 = nullptr;
char* a2 = nullptr;
double* a3 = nullptr;
Func(0); // 调用Func(int n)
Func(NULL); // 调用Func(int n),不符合预期
Func(nullptr); // 使用nullptr 解决问题
std::cout << "Hello World!\n";
}
如上代码所示:Func(NULL)调用的是Func(int n)不符合预期,预期是调用Func(void* p),所以加入nullptr来解决问题。nullptr的类型为nullptr_t,能够隐式地转换为任何指针或成员指针的类型,也能和他们进行相等或者不等的比较。
4、constexpr(常量表达式)
constexpt关键字的作用是使指定的常量表达式在程序编译阶段就计算出其结果,这可以大大提高程序的执行效率,因为表达式只需要在编译阶段计算一次,节省了每次程序运行时都需要计算一次的时间。非常量表达式与之相反,只能在程序运行阶段计算出结果。
C++ 11 标准中,constexpr 可用于修饰普通变量、函数(包括模板函数)以及类的构造函数。
(1)constexpr修饰普通变量
// constexpr 修饰普通变量
constexpr int N = 1 + 2 + 3;
int arr[N] = {0};
(2)constexpr修饰函数的返回值,这样的函数成为"常量表达式函数"。
注意:constexpr并非可以修饰任何函数的返回值,函数必须满足4个条件。
1)函数必须有返回值,返回值不能为void。
constexpr void display() {
//函数体
}
该函数不是“常量表达式函数”。
2)整个函数的函数体中,除了可以包含 using 指令、typedef 语句以及 static_assert 断言外,只能包含一条 return 返回语句
constexpr int display(int x) {
int ret = 1 + 2 + x;
return ret;
}
3)函数在使用之前,必须有对应的定义语句。我们知道,函数的使用分为“声明”和“定义”两部分,普通的函数调用只需要提前写好该函数的声明部分即可(函数的定义部分可以放在调用位置之后甚至其它文件中),但常量表达式函数在使用前,必须要有该函数的定义。
#include <iostream>
using namespace std;
// 常量表达式函数的声明
constexpr int Display(int x);
// 常量表达式函数的定义
constexpr int Display(int x)
{
int ret = 1 + 2 + x;
return ret;
}
int main()
{
// int n = 5;
// n是变量,进行如下声明时,报错
// int arr[n] = {0};
// constexpr 修饰普通变量
constexpr int N = 1 + 2 + 3;
int arr[N] = {0};
int a[Display(1)] = { 1,2,3,4};
cout << a[2] << endl;
std::cout << "Hello World!\n";
}
4)return 返回的表达式必须是常量表达式
#include <iostream>
using namespace std;
// 常量表达式函数的声明
constexpr int Display(int x);
// 常量表达式函数的定义
constexpr int Display(int x)
{
int ret = 1 + 2 + x;
return ret;
}
int NUM = 3;
constexpr int Play(int x)
{
return NUM + x;
}
int main()
{
// int n = 5;
// n是变量,进行如下声明时,报错
// int arr[n] = {0};
// constexpr 修饰普通变量
constexpr int N = 1 + 2 + 3;
int arr[N] = {0};
int a[Display(1)] = { 1,2,3,4};
cout << a[2] << endl;
// 报错:NUM的值不可用作常量
/* int b[Play(0)] = { 1,2,3,4 };
cout << a[2] << endl;*/
std::cout << "Hello World!\n";
}
(3)修饰类的构造函数
对于strcut或者class 不能用constexpr来修饰,如下
// 错误:constexpr在此处无效
constexpr struct MyType
{
const char* name;
int age;
};
正确的做法应该是在该类型的内部添加一个常量构造函数。如下所示:
struct MyType
{
constexpr MyType(const char* name, int age) : name(name), age(age) {}
const char* name;
int age;
};
注意,constexpr 修饰类的构造函数时,要求该构造函数的函数体必须为空,且采用初始化列表的方式为各个成员赋值时,必须使用常量表达式。
(4)constexpr修饰模板函数
//模板函数
template <typename T>
constexpr T dispaly(T t) {
return t;
}
(5)constexpr修饰指针
const int *p1=nullptr; //常量指针
constexpr int *p2=nullptr; //constexpr只能在开头,等效于指针常量(和const相反)
(等效于 int *const p2=nullptr;)
5、类型别名声明
C++11使用using 来声明别名,这样比以往声明别名的方法更为简单。如下
template<typename T>
using map_str_tNew = std::map<std::string, T>;
在这里使用using给std::map<std::string, T>;模板取了别名:map_str_tNew 。接下来就可以这样使用
map_str_tNew map;
6、auto自动类型推导
C++11中用auto关键字来支持自动类型推导。也就是在编译期间自动推导出变量的类型。
使用auto时必须对变量进行初始化。
auto 关键字的语法如下:auto name = value
auto 用法举例如下
auto n = 10;
auto m = 10.2;
auto p = &n;
auto url = "https://www.baidu.com/";
n 变量被自动推导为int,并且被赋初值为10;
m 变量被自动推导为double,并且被赋初值为10.2;
m 变量被自动推导为int*,并且指向为n的地址;
url 变量被自动推导为const char*,并且初始化为"https://www.baidu.com/";
7、decltype类型推导
decltype和auto一样都是在编译时期进行自动类型推导。既然有了auto为什么还要有decltype呢?因为auto并不适用于所有的自动类型推导。auto和decltype都可以推导出变量的类型但是他们的用法不相同:
auto valname = value;
decltype(exp) valname = value;
其中valname 是变量名,value 是赋给变量的值,exp是表达式。auto是根据=右边的值推导出变量的类型。decltype是根据exp表达式推导出变量的类型,和=右边的值没有关系。另外auto要求变量必须初始化,但是decltype没有要求。