Back to VNotes

C++ / Syntax

现代 C++ 语法笔记(一)

整理原始字面量、long long、成员初始化、模板、异常等现代 C++ 语法点。

现代C++

原始字面量

在定义字符串时可以定义为原始字面量,编译器会忽略其中的转义字符,还能用于省略连接符

语法

R"xxx(原始字面量)xxx";

括号两边的内容会被忽略,但两边内容必须相同

例:

当我们要表示路径时,由于\会发生转义,就需要写\\,使用原始字面量可以避免

string s = R"(C:\Desktop)";

字符串写到不同行的时候,需要用\连接,若定义为原始字面量就不用连接符

string s = "a\
	b\
	";

等价于

string s = R"(a
	b
	)";

long long

至少有64位,根据平台决定

<limits>中可以根据宏LLONG_MAX / LLONG_MIN查看最大/最小值

long long num = 66666666LL

后面的LL声明显式告诉编译器这一串数字是long long类型;unsigned long long 则是ull;不分大小写

不同整型一起计算(如相加)时:

长度越大的整型等级越高,比如 long long int 的等级会高于int。
长度相同的情况下,标准整型的等级高于扩展类型,比如 long long int 和 int64 如果
都是64 位长度,则long long int类型的等级更高。
相同大小的有符号类型和无符号类型的等级相同,long long int 和unsigned longlong 
int的等级就相同。
转换过程中,低等级整型需要转换为高等级整型,有符号的需要转换为无符号整形。

类成员的就地初始化

对于非静态成员的初始化,可以直接在类内使用 ={} 进行初始化,而静态成员,只有被设置为常量时才能就地赋值

class object{
	int a = 1;
	char b = '1';
	int c{2};
	int d = {3};
	
	static int e = 4;   //错误,必须被定义为常量
	static const int f = 4;  //static const 与 const static 无区别
};

但如果在构造函数中也对变量进行了赋值,构造函数中的值会覆盖就地初始化的值,初始化列表(效率比直接在构造函数内赋值高)也是如此

final关键字

用于限制某个类不能再被继承或限制虚函数不能再被重写,用法与override相似

class A
{
	virtual void func(){}
};

class B:public A final  //不能被继承
{
	void func() final{} //不能再被继承于B的类重写
};

模板的优化

多个 > 的解析

当遇到多个 > 时,按之前的标准,>>会被理解为右移运算符

list<vector<int>>,在C++11中,则会尽可能的将多个>理解为模板参数结束符

函数模板默认参数

函数模板也可以有默认参数,且无需和其它默认参数一样,必须在参数列表的最右侧

当所有模板参数都有默认参数时,函数模板的调用如同一个普通函数。但对于类模板而言,哪怕所有参数都有默认参数,在使用时也必须在模板名后跟随<>来实例化,这样一来,函数模板的使用就会变得非常灵活

例:

template <typename R = int, typename N>
R func(N arg)
{
    return arg;
}

auto ret1 = func(520);                        R为默认int  N为520推导int
cout << "return value-1: " << ret1 << endl;   输出: 520

auto ret2 = func<double>(52.134);             R为传入的double  N为52.1314推导double
cout << "return value-2: " << ret2 << endl;   输出: 52.1314

auto ret3 = func<int>(52.134);                R为传入的int  N为52.1314推导double
cout << "return value-3: " << ret3 << endl;   输出: 52

auto ret4 = func<char, int>(100);             R为传入的char  N为传入的int
cout << "return value-4: " << ret4 << endl;   输出: d

当默认模板参数和模板参数自动推导同时使用时(优先级从高到低):

  • 如果可以推导出参数类型则使用推导出的类型
  • 如果函数模板无法推导出参数类型,那么编译器会使用默认模板参数
  • 如果无法推导出模板参数类型并且没有设置默认模板参数,编译器就会报错。

例:

template <typename T>
void func(T arg1 = 100)
{
    cout << "arg1: " << arg1 << endl;
}

func('a');
func(97);
func();        无实参用于类型推导,编译报错
  • 模板参数类型的自动推导是根据模板函数调用时指定的实参进行推断的,没有实参则无法推导
  • 模板参数类型的自动推导不会参考函数参数列表中指定的默认参数。