Table of Contents:

c++14

泛型的 lambda

在 C++14 里,lambda 表达式又多了一项新本领,可以实现“泛型化”,相当于简化了的模板函数,具体语法还是利用了“多才多艺”的 auto

auto f = [](const auto& x) // 参数使用auto声明,泛型化
{
    return x + x;
};
cout << f(3) << endl; // 参数类型是int
cout << f(0.618) << endl; // 参数类型是double
string str = "matrix";
cout << f(str) << endl; // 参数类型是string

make_index_sequence

 实现编译期的整数序列,如下例make_index_sequence<3>()会使fun函数的模板参数: int... N 推演为:0,1,2序列 :

#include <iostream> 
#include <tuple>
 
using namespace std;
 
template<int... N>
decltype(auto) fun(index_sequence<N...> is) {
    return make_tuple(N...);
}
 
int main() {
 
    auto t = fun(make_index_sequence<3>());
    cout << std::get<0>(t) << endl;
    cout << std::get<1>(t) << endl;
    cout << std::get<2>(t) << endl;
    return 0;
}

c++17

std::optional

场景:如果有这样一个函数,通过返回值来判断计算结果是否有效,如果结果有效,才能使用结果

bool div_int(int a, int b, int &result) {
    if (b == 0) {
        return false;
    }
    result = a / b;
    return true;
}

这样的使用方式很不方便,需要两个变量来描述结果。这种场景下应该使用c++17中的std::optional。

//div_int可以通过optional优化:optional中,结果是否有效和结果都保存在其中
std::optional<int> div_int(int a, int b) {
    if (b != 0) {
        return std::make_optional<int>(a / b);
    }
    return {};
}


TEST_F(optional) {
    auto ret = div_int(2, 1);
    ASSERT(ret);
    ASSERT_EQ(2, ret.value()); // 如果ret为true, 直接从ret中获取结果


    auto ret2 = div_int(2, 0);
    ASSERT(!ret2); // 结果无效


    // 如果ret2为false,获取访问value将会 抛出异常
    try {
        ret2.value();
    } catch (std::exception e) {
        std::cout << e.what() << std::endl;
    }
}

std::variant

c++17中引入了std::variant。std::variant类似union

using IntFloatString = std::variant<int, float, std::string>; // 定义支持int、float、string三个类型,并取一个别名
//初始化一个variant
TEST_F(InitVariant) {


    IntFloatString i = 10;
    ASSERT_EQ(10, std::get<int>(i) );
    ASSERT_EQ(10, std::get<0>(i) );
    std::cout << i.index(); // prints   0,  即第几个位置设置了值


    IntFloatString f = 20.0f;
    ASSERT_EQ(20.0f, std::get<float>(f) );


    IntFloatString s = "hello world";
    ASSERT_EQ("hello world", std::get<std::string>(s));
}

constexpr if

用于泛型编程中的条件判断

template <int N, int... Ns>
auto sum()
{
    if constexpr (0 == sizeof...(Ns))
        return N;
    else
        return N + sum<Ns...>();
}


// 调用
sum<1, 2, 3>(); // returns 6

string_view

string存在的问题:
1. 使用std::string的接口,字符串字面值、字符数组、字符串指针的传递仍要数据拷贝
2. substr O(n)复杂度

string_view是c++17标准库提供的一个类,它提供一个字符串的视图,即可以通过这个类以各种方法“观测”字符串,但不允许修改字符串。它内部只保存一个指针长度,无论是拷贝,还是修改,都非常廉价
构造求substr都是O(1)的复杂度。

std的string的构造不可避免的会设计内存分配和拷贝。而string_view只是一个字符串的视图,构造函数可以避免拷贝,做到O(1)复杂度。

更改视图的大小
类中提供了两个函数remove_suffix(从后面缩减大小)和remove_prefix(从前方缩减大小),可以缩减视图的大小。

string_view sv("123456789");
sv.remove_suffix(1);    // 现在sv中为:12345678, sv的大小为8
sv.remove_prefix(2);    // 现在sv中为: 345678, sv的大小为6

当然他还提供了其他的一些string具有的方法,方便对原始的字符串进行操作。

注意点:

1. 因为string_view并不拷贝内存,所以要特别注意它所指向的字符串的生命周期。string_view指向的字符串,不能再string_view死亡之前被回收。这跟悬挂指针(dangling pointer)或悬挂引用(dangling references)很像
比如:

string_view foo() {
    std::string s{"hello world"};
    return string_view{s};
}

推荐的使用方式:仅仅作为函数参数,因为如果该参数仅仅在函数体内使用而不传递出去,这样使用是安全的。这样使用,函数的参数可以接收字符串字面值、字符数组、字符串指针、std::string,而不用拷贝

std::invoke  std::apply

* apply
Invoke the Callable object f with a tuple of arguments.

c++20 

模组(Modules)
协程(Coroutines)
标准库 Concepts 的概念
范围(range)
constexpr支持:new/ delete、dynamic_cast、try/ catch、虚拟
constexpr 向量和字符串
计时:日历、时区支持
std::format
std::span
std::jthread