好奇的探索者,理性的思考者,踏实的行动者。
Table of Contents:
在 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<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;
}
场景:如果有这样一个函数,通过返回值来判断计算结果是否有效,如果结果有效,才能使用结果
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;
}
}
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));
}
用于泛型编程中的条件判断
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存在的问题:
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,而不用拷贝
* apply
Invoke the Callable object f with a tuple of arguments.
模组(Modules)
协程(Coroutines)
标准库 Concepts 的概念
范围(range)
constexpr支持:new/ delete、dynamic_cast、try/ catch、虚拟
constexpr 向量和字符串
计时:日历、时区支持
std::format
std::span
std::jthread