前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++17常用新特性(八)---其他不常用语言特性

C++17常用新特性(八)---其他不常用语言特性

作者头像
CPP开发前沿
发布2022-04-13 15:33:07
7240
发布2022-04-13 15:33:07
举报
文章被收录于专栏:CPP开发前沿

C++17版本中,标准委员会同时对一些小的特性进行发布。在本文中,将对一些细小的特性进行梳理。欢迎批评指正。

1 嵌套命名空间

熟悉C#或者Java的同学可能对嵌套命名空间并不陌生,但是C++中的嵌套命名空间却一直等到17版本的发布在正式支持。在编码时,下面两种写法其实是一样的。

代码语言:javascript
复制
namespace A::B::C{
}

等价于

代码语言:javascript
复制
namespace A{
  namespace B{
    namespace C{
    }
  }
}

2 静态断言static_assert

C++11中引入了静态断言关键字,定义格式为static_assert(表达式,"提示字符串"),主要是当表达式不成立时产生一条编译错误。如下面的代码所示:

代码语言:javascript
复制
int main()
{
    static_assert(1!=1,
        "表达式需要相等");
    return 0;
}

编译时编译器报错类型为:

C++17后,静态断言发布了新的版本,提示字符串可以进行省略。如:

代码语言:javascript
复制
int main()
{
    static_assert(1!=1);
    return 0;
}

编译时,编译器会提示错误,但是具体的提示信息不是用户定义的,完全依赖平台。

3 预处理条件 __has_include

C++17版本发布后,同时也扩展了预处理指令,使用后可以检查文件是否被包含。如下面的功能:

代码语言:javascript
复制
#if __has_include(<mfcApi>)
#define NUMBER "ONE"
#elif __has_include(<iostream>)
#define NUMBER "TWO"
#endif

需要关注的是,由于它是预处理指令是不能放在源代码中的。如果对上面的定义进行测试,编写代码为:

代码语言:javascript
复制
int main()
{
    cout<<"NUMBER="<<NUMBER<<endl;
    return 0;
}

代码运行结果为:NUMBER=TWO

4 auto类型列表初始化

C++17对使用auto进行列表初始化做了很大的改动。从某种程度说是一种破坏性的改动,因为,伴随着这一改动,之前相关代码的行为也会发生变化。一些主流的编译器也已经支持了这一改动。如:vs2015、g++5以及clang3.8及以后的版本。

从c++11开始,引入了花括号进行统一初始化,在花括号前是否使用等号也代表着不同的含义,如下代码所示:

代码语言:javascript
复制
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后面使用=号表示的是一个初始化列表,但如果不加=号,相同的表达式不一样。具体如下面代码所示:

代码语言:javascript
复制
auto i{42};//表示初始化整型变量
auto i{42,34};//表示整形列表
auto i={42};//表示整形列表
auto i={42,34};//表示整形列表

5 十六进制浮点数字面量

使用10进制数表示浮点数时并不能准确的知道数据的保存精度,鉴于此,C++17中提供了16进制的浮点数字面量,可以帮助我们处理需要精确的浮点数的场景。

十六进制浮点数定义格式如下:

  • 有效数字/尾数用十六进制书
  • 指数部分用十进制书写,表示乘以 2 的 n 次幂

写法及转换成10进制数据方式如下:

代码语言:javascript
复制
double d = 0x1.2p3;//转换成10进制数为:9.0

上面十六进制转换成浮点数的计算公式为:(1+2/16)*2的3次幂。

再如:

代码语言:javascript
复制
0xC.68p+3  = (12  + 6/16 + 8/16/16 )*2^3;

6 utf-8字符字面常量

从 C++11 起, C++ 就已经支持以 u8 为前缀的 UTF­8 字符串字面量,直到C++17版本发布后,才支持单字符的字面常量,可以按照下面的方式进行编写。

代码语言:javascript
复制
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之后就表示不同的函数了。

代码语言:javascript
复制
void fFunThrow();
void fFunNoexcept() noexcept; // 不 同 类 型

在C++17前可以通过同一个函数指针进行使用,但是之后,如果使用同一个函数指针分别指向这两个函数,将会报错。

同理,在对基类函数进行重载时,如果派生类没有添加异常声明类型,编译器也是会报错的。如:

代码语言:javascript
复制
class CBase {
public:
    virtual void foo() noexcept;
};
class Derived : public CBase {
public:
    void foo() override; //编译报错:不 能 重 载
};

8 总结

对于C++17版本中新增或者修改的新的特性如果需要进行深入研究,可以参考网站:https://zh.cppreference.com/。欢迎大家留言指导!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CPP开发前沿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档