IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++ 17 新特性理解 -> 正文阅读

[C++知识库]c++ 17 新特性理解

1构造函数模板推导

在C++17前构造一个模板类对象需要指明类型:

pair<int, double> p(1, 2.2); // before c++17

std::tuple<int, double, std::string> tq(64, 128.0, "Caroline");?

C++17就不需要特殊指定,直接可以推导出类型,代码如下:std::tuple eee(64, 128.0, "Caroline");

pair p(1, 2.2); // c++17 自动推导
vector v = {1, 2, 3}; // c++17

如果是tuple, 则是? std::tuple eee(64, 128.0, "Caroline");?

2.结构化绑定(Structured bindings)

结构化绑定提供了类似其他语言中提供的多返回值的功能。到目前为止,我们可以通过 std::tuple 来构造一个元组,囊括多个返回值。但缺陷是显而易见的,我们没有一种简单的方法直接从元组中拿到并定义元组中的元素,尽管我们可以使用 std::tie 对元组进行拆包,但我们依然必须非常清楚这个元组包含多少个对象,各个对象是什么类型。

std::tuple<int,double,std::string> f() {
? ? return std::make_tuple(1,2.3,"456");
}
auto [x,y,z] = f(); // x,y,z 分别被推导为int,double,std::string

结构化绑定还可以改变对象的值,使用引用即可:

// 进化,可以通过结构化绑定改变对象的值
int main() {
    std::pair a(1, 2.3f);
    auto& [i, f] = a;
    i = 2;
    cout << a.first << endl; // 2 
}

注意结构化绑定不能应用于constexpr

constexpr auto[x, y] = std::pair(1, 2.3f); // compile error, C++20可以

?结构化绑定不止可以绑定pair和tuple,还可以绑定数组和结构体等

int array[3] = {1, 2, 3};
auto [a, b, c] = array;
cout << a << " " << b << " " << c << endl;

// 注意这里的struct的成员一定要是public的
struct Point {
    int x;
    int y;
};
Point func() {
    return {1, 2};
}
const auto [x, y] = func();

3.if-switch语句初始化?

C++17前if语句需要这样写代码:

int a = GetValue();
if (a < 101) {
    cout << a;
}
// if (init; condition)

if (int a = GetValue()); a < 101) {
    cout << a;
}

?4.内联变量

C++17前只有内联函数,现在有了内联变量,我们印象中C++类的静态成员变量在头文件中是不能初始化的,但是有了内联变量,就可以达到此目的:

// header file
struct A {
    static  int value;  
};
inline int  A::value = 10;

// ==========或者========
struct A {
    inline static  int value = 10;
}

5.折叠表达式

C++17引入了折叠表达式使可变参数模板编程更方便:

template <typename ... Ts>
auto sum(Ts ... ts) {
    return (ts + ...);
}
int a {sum(1, 2, 3, 4, 5)}; // 15
std::string a{"hello "};
std::string b{"world"};
cout << sum(a, b) << endl; // hello world

?6.constexpr lambda表达式

C++17前lambda表达式只能在运行时使用,C++17引入了constexpr lambda表达式,可以用于在编译期进行计算。

int main() { // c++17可编译
    constexpr auto lamb = [] (int n) { return n * n; };
    static_assert(lamb(3) == 9, "a");
}

注意:constexpr函数有如下限制:

函数体不能包含汇编语句、goto语句、label、try块、静态变量、线程局部存储、没有初始化的普通变量,不能动态分配内存,不能有new delete等,不能虚函数。

7.namespace嵌套

namespace A {
    namespace B {
        namespace C {
            void func();
        }
    }
}

// c++17,更方便更舒适
namespace A::B::C {
    void func();)
}

8.__has_include预处理表达式

可以判断是否有某个头文件,代码可能会在不同编译器下工作,不同编译器的可用头文件有可能不同,所以可以使用此来判断。

int main()
{
#if __has_include(<cstdio>)
? ? printf("hehe");
#endif
#if __has_include("iostream")
? ? std::cout << "hehe" << std::endl;
#endif
return 0;
}

9.在lambda表达式用*this捕获对象副本

正常情况下,lambda表达式中访问类的对象成员变量需要捕获this,但是这里捕获的是this指针,指向的是对象的引用,正常情况下可能没问题,但是如果多线程情况下,函数的作用域超过了对象的作用域,对象已经被析构了,还访问了成员变量,就会有问题。

struct A {
    int a;
    void func() {
        auto f = [this] {
            cout << a << endl;
        };
        f();
    }  
};
int main() {
    A a;
    a.func();
    return 0;
}

所以C++17增加了新特性,捕获*this,不持有this指针,而是持有对象的拷贝,这样生命周期就与对象的生命周期不相关啦。

struct A {
    int a;
    void func() {
        auto f = [*this] { // 这里
            cout << a << endl;
        };
        f();
    }  
};
int main() {
    A a;
    a.func();
    return 0;
}

10.新增Attribute

我们可能平时在项目中见过declspec, __attribute?, #pragma指示符,使用它们来给编译器提供一些额外的信息,来产生一些优化或特定的代码,也可以给其它开发者一些提示信息。

例如:

struct A { short f[3]; } __attribute__((aligned(8)));

void fatal() __attribute__((noreturn));

?[[fallthrough]],用在switch中提示可以直接落下去,不需要break,让编译期忽略警告

[[nodiscard]] :表示修饰的内容不能被忽略,可用于修饰函数,标明返回值一定要被处理

[[maybe_unused]] :提示编译器修饰的内容可能暂时没有使用,避免产生警告

11.字符串转换

新增from_chars函数和to_chars函数

?? ?const std::string str{ "123456098" };
?? ?int value = 0;
?? ?const auto res = std::from_chars(str.data(), str.data() + 4, value);

? ?则 :value = 1234;

? ? ? ? ? ?res.ptr= 56098;

12.std::variant

具体见:CSDNicon-default.png?t=L892https://mp.csdn.net/mp_blog/creation/editor/120419967

C++17增加std::variant实现类似union的功能,但却比union更高级,举个例子union里面不能有string这种类型,但std::variant却可以,还可以支持更多复杂类型,如map等。

注意,不允许使用空变量、具有引用成员的变量、具有c样式数组成员的变量和具有不完整类型(如void)的变量。没有空的状态:这意味着对于每个构建的对象,必须至少调用一个构造函数。默认构造函数初始化第一个类型(通过第一个类型的默认构造函数):

1.默认情况下,变量的默认构造函数调用第一个备选项的默认构造函数:

2.成员函数index()可用于查明当前设置了哪个选项(第一个选项的索引为0)。

3.访问值的通常方法是调用get<>()获取对应的选项值。可以传递它的索引或者类型

#include <variant>
?
std::variant<int, std::string> var{"hi"}; // initialized with string alternative
std::cout << var.index(); // prints 1
var = 42; // now holds int alternative
std::cout << var.index(); // prints 0

var = "world";
...
try {
std::string s = std::get<std::string>(var); // access by type? ?

std::cout << s << std::endl;? ?//world

var = 3;
int i = std::get<0>(var); // access by index? ??

std::cout << i?<< std::endl;? ?//3
}
catch (const std::bad_variant_access& e) { // in case a wrong type/index is used

如果没有为第一个类型定义默认构造函数,则调用该变量的默认构造函数会在编译时错误:
#include <iostream>
#include <variant>
?
struct NoDefConstr
{
? ? NoDefConstr(int i)
? ? {
? ? ? ? std::cout << "NoDefConstr::NoDefConstr(int) called\n";
? ? }
};
?
int main()
{
? ? std::variant<NoDefConstr, int> v1; // ERROR: can’t default construct first type
?
? ? return 0;

不过辅助类型std::monostate提供了处理这种情况的能力,还提供了模拟空状态的能力。

std::monostate
为了支持第一个类型没有默认构造函数的variant对象,提供了一个特殊的helper类型:std::monostate。类型std::monostate的对象总是具有相同的状态,因此,它们总是相等的。它自己的目的是表示另一种类型,这样variant就没有任何其他类型的值。也就是说,std::monostate可以作为第一种替代类型,使变体类型默认为可构造。

std::variant<std::monostate, NoDefConstr> v2; // OK
std::cout << "index: " << v2.index() << '\n'; // prints 0

4.赋值和emplace()操作对应于初始化:

std::variant<int, int, std::string> var; // sets first int to 0, index()==0
var = "hello"; // sets string, index()==2
var.emplace<1>(42); // sets second int, index()==1

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-23 11:16:21  更:2021-09-23 11:18:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 22:40:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码