C++20新特性总结

preview

一、The Big Four

1.1 Concepts

C++中模板编程极大地简化了代码的编写,但同时也会带来一些使用上的疑惑,例如一下代码片段,判断两个数是否相等,只要是重载了==运算符,自定义类型也可以使用该模板实例化对应的比较函数:

/**
 * @file     comcept.cpp
 * @brief    
 * @author   YongDu
 * @date     2021-07-20
 */

template <typename T>
auto isEqual(T left, T right) {
   
  return left == right;
}

int main() {
   
  cout << std::boolalpha;

  double a = 2.334;
  double b = 2.335;

  cout << isEqual(2, 2) << endl;         // true
  cout << isEqual(b - a, 0.001) << endl; // false

  return 0;
}

我们知道,浮点数因为在存储中涉及精度问题,所以不能直接去判断两个浮点数是否想定,需要自定义精度去判断。模板函数依然可以正确执行,但结果却不是我们想要的,因此我们需要使用该模板的类型做一些限制。假如说我们限定次函数的类型为整型,当然,这只是举个例子,如果单纯地限定为整型,也就没有使用模板的必要。我们可以采用C++11中的静态断言static_asser,该断言会在编译期执行检测,判断类型是否为整型,如下:

template <typename T>
auto isEqual(T left, T right) {
   
  static_assert(std::is_integral<T>::value);
  return left == right;
}

此时使用浮点数进行比较,便会触发断言,编译失败,如下图所示。还有个问题就是此时断言在函数内部,也就是说必须通过模板实例化对应函数,然后执行该函数时才能触发断言,某些情况下很可能编译成功,在运行期才会发生错误。

image-20210720205023474

C++17提供了concept机制,用来检查模板参数类型,代码如下:

template <typename T>
concept Integeral = std::is_integral<T>::value;

template <Integeral T>
auto isEqual(T left, T right) {
   
  return left == right;
}

int main() {
   
  cout << std::boolalpha;

  double a = 2.334;
  double b = 2.335;

  cout << isEqual(2, 2) << endl;         // true
  cout << isEqual(b - a, 0.001) << endl; // false

  return 0;
}

image-20210720205650294

此时的报错信息更清晰,方便了我们去排查错误。如上的concept使用方法还有以下3种写法,效果是一样的,有人推崇第四种写法,省略了typename关键字,但是我觉得第一种写法更清晰:

// #2
template <typename T>
requires Integeral<T>
auto isEqual(T left, T right) {
    return left == right; }

// #3
template <typename T>
auto isEqual(T left, T right) requires Integeral<T> {
   
  return left == right;
}

// #4
Integeral auto isEqual(Integeral auto left, Integeral auto right) {
    return left == right; }

1.2 Range library

ranges:代表一段元素,之前版本使用beginend标识一段元素,那么用ranges有什么好处呢?

  • 简化语法和操作;
  • 防止begin,end迭代器的不配对使用;
  • 使得类似管道|的串行操作成为可能。

相关概念:

  • View:延迟计算,只有读权限
  • Actions:即时处理,读或写
  • Algorithms:操作range
  • Views和Actions的串联操作

具体看代码(需要包含<ranges>头文件):

简化操作:

std::sortstd::ranges::sort比较

std::vector<int> vec{
   3, 1, 2, 5, 6, 4};

// std::sort()
std::sort(vec.begin(), vec.end());
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>{
   cout, " "}); // 1 2 3 4 5 6

// ranges::sort()
std::ranges::sort(vec);
std::ranges::copy(vec, std::ostream_iterator<int>{
   cout, " "}); // 1 2 3 4 5 6

串联视图:

定义了一个vector,even用来筛选偶数,square返回参数的平方

std::vector<int> vec{
   1, 2, 3, 4, 5, 6};

auto even = [](int i) {
    return i % 2 == 0; };
auto square = [](int i) {
    return i * i; };

auto result = vec | std::views::filter(even) | std::views::transform(square);
/* 此时 result 并没有被计算,只是定义了一系列视图,只有到下面的遍历操作时,result 触发,即所谓延迟计算 */
for (auto i : result) {
   
    cout << i << " "; // 4 16 36
}

过滤和变换:

std
  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值