C++17版本中,标准委员会同时对一些小的特性进行发布。在本文中,将对一些细小的特性进行梳理。欢迎批评指正。
1 嵌套命名空间
熟悉C#或者Java的同学可能对嵌套命名空间并不陌生,但是C++中的嵌套命名空间却一直等到17版本的发布在正式支持。在编码时,下面两种写法其实是一样的。
namespace A::B::C{
}
等价于
namespace A{
namespace B{
namespace C{
}
}
}
2 静态断言static_assert
C++11中引入了静态断言关键字,定义格式为static_assert(表达式,"提示字符串"),主要是当表达式不成立时产生一条编译错误。如下面的代码所示:
int main()
{
static_assert(1!=1,
"表达式需要相等");
return 0;
}
编译时编译器报错类型为:
C++17后,静态断言发布了新的版本,提示字符串可以进行省略。如:
int main()
{
static_assert(1!=1);
return 0;
}
编译时,编译器会提示错误,但是具体的提示信息不是用户定义的,完全依赖平台。
3 预处理条件 __has_include
C++17版本发布后,同时也扩展了预处理指令,使用后可以检查文件是否被包含。如下面的功能:
#if __has_include(<mfcApi>)
#define NUMBER "ONE"
#elif __has_include(<iostream>)
#define NUMBER "TWO"
#endif
需要关注的是,由于它是预处理指令是不能放在源代码中的。如果对上面的定义进行测试,编写代码为:
int main()
{
cout<<"NUMBER="<<NUMBER<<endl;
return 0;
}
代码运行结果为:NUMBER=TWO
4 auto类型列表初始化
C++17对使用auto进行列表初始化做了很大的改动。从某种程度说是一种破坏性的改动,因为,伴随着这一改动,之前相关代码的行为也会发生变化。一些主流的编译器也已经支持了这一改动。如:vs2015、g++5以及clang3.8及以后的版本。
从c++11开始,引入了花括号进行统一初始化,在花括号前是否使用等号也代表着不同的含义,如下代码所示:
int i{42};//整型变量
int i={42,24};//编译报错
auto i{42};//C++17前表示一个列表,C++17开始,表示初始化整型变量
auto i{42,34};//C++11表示整形列表,C++17开始,会报错,
从C++17开始,在auto后面使用=号表示的是一个初始化列表,但如果不加=号,相同的表达式不一样。具体如下面代码所示:
auto i{42};//表示初始化整型变量
auto i{42,34};//表示整形列表
auto i={42};//表示整形列表
auto i={42,34};//表示整形列表
5 十六进制浮点数字面量
使用10进制数表示浮点数时并不能准确的知道数据的保存精度,鉴于此,C++17中提供了16进制的浮点数字面量,可以帮助我们处理需要精确的浮点数的场景。
十六进制浮点数定义格式如下:
写法及转换成10进制数据方式如下:
double d = 0x1.2p3;//转换成10进制数为:9.0
上面十六进制转换成浮点数的计算公式为:(1+2/16)*2的3次幂。
再如:
0xC.68p+3 = (12 + 6/16 + 8/16/16 )*2^3;
6 utf-8字符字面常量
从 C++11 起, C++ 就已经支持以 u8 为前缀的 UTF8 字符串字面量,直到C++17版本发布后,才支持单字符的字面常量,可以按照下面的方式进行编写。
auto c = u8'v';
char b = u8'm';
在这里需要说明的是C++不同的版本对使用u8后转换的字符类型定义是不一样的,如:在 C++17 中, u8'6' 的类型是 char,在 C++20 中可能会变为 char8_t。因此在此推荐统一使用auto关键字定义。
7 异常声明作为类型的一部分
C++17之前的版本中,noexcep并不作为类型的一部分,因此声明相同参数和返回值类型的函数时,无论有没有加上这个关键字,两个函数类型其实是等价的,但是这种情况从C++17开始,就不存在了。且编译器遵循严格类型约束,不恰当的使用将会报错。如下面定义的函数,C++17之后就表示不同的函数了。
void fFunThrow();
void fFunNoexcept() noexcept; // 不 同 类 型
在C++17前可以通过同一个函数指针进行使用,但是之后,如果使用同一个函数指针分别指向这两个函数,将会报错。
同理,在对基类函数进行重载时,如果派生类没有添加异常声明类型,编译器也是会报错的。如:
class CBase {
public:
virtual void foo() noexcept;
};
class Derived : public CBase {
public:
void foo() override; //编译报错:不 能 重 载
};
8 总结
对于C++17版本中新增或者修改的新的特性如果需要进行深入研究,可以参考网站:https://zh.cppreference.com/。欢迎大家留言指导!