背景

逛水木社区C++版块,看到了一篇很有意思的帖子--《C++20会变得陌生》。楼主贴出了分别用C++11 和 C++20编写的代码,如下:

void cpp_11() {
    std::vector<int> v{1, 2, 3, 4, 5};

    std::vector<int> even;
    std::copy_if(v.begin(), v.end(), std::back_inserter(even),
                 [](int i) { return i % 2 == 0; });

    std::vector<int> results;
    std::transform(even.begin(), even.end(),
                   std::back_inserter(even),
                   [](int i) { return i * 2; });

    for (int n : results) std::cout << n << ' ';
}

void cpp_20() {
    std::vector<int> v{1, 2, 3, 4, 5};
    v | ranges::view::filter([](int i) { return i % 2 == 0; })
      | ranges::view::transform([](int i) { return i * 2; })
      | ranges::view::foreach([](int i) { std::cout << i << ' '; });
}

以上代码实现了数据操作:

  1. 从向量v里筛选出偶数的元素
  2. 将以上得到的每个元素分别乘以2
  3. 将以上得到的每个元素分别打印出来

C++11 通过使用algorithm里的几个函数按步骤实现;而C++20 通过使用新的ranges扩展实现了相同的效果,通过使用|将数据连接了起来,类似于Unix shell的管道。

我猜作者的意思应该是想表达C++20变化大,会让一些人感到陌生,但下面的评论就很有意思了,大体有以下几类:
1.“颜值派”:这语法可真丑
2.“保守派”:C++在函数式编程上路越来越作死
3.“逃离派”:建议使用RustGo替代越来越臃肿的C++
4.“现实派”:C++真是越来越复杂了,连语法都看不懂,哪一天会撑爆
5.“理性派”:C++的一些痛点必须解决,而目前看来也只能这样解决

几点看法

近几年,C++的演进进入了快车道,之前C++98到C++11,历时13年;现在C++11、C++14、C++17、C++20,每3年一版,带来了改进的同时,也引起了众多的吐槽,比如上面的评论。现在是我的一些看法,为了避免发散,针对上面的代码做讨论。

关于语法

美丑永远是相对的,得看你跟谁比。比如,如果简洁是一种美,那跟纯函数式语言Haskell比,肯定要丑了,下面是Haskell等价的代码,很明显要简洁的多。

[1,2,3,4,5] & filter even & map (*2) & mapM_ print

跟C语言比呢?如果抽象是一种美,我觉得C++要美观的多,比如C中只能通过循环来实现遍历,而现代C++中已经有了很多结构控制函数,比如foreachfilter等,这种函数望文生义,你很明白就能知道代码在干什么,而循环语句则需要你进到循环内部才能明白在做什么。我是从C转向C++的,起初写C++代码的时候,根本就不用引用、namespace这些东东,而是用指针和命名前缀代替,当时也觉得不美。久而久之发现,指针传参的时候要判断指针是否为空,这样的代码真的很丑,那么长的标识符也很丑,而引用和名字空间恰好解决了这些问题,反倒是觉得好看了。

C++20 跟 C++11比呢?C++ 20美,因为上文的代码既简洁,又清晰了表达了代码意图。

C++语法是有巨大的历史包袱的,想进步很难,但C++在语法上面是在进步的,比如使用{}统一初始化语句,虽然初看起来比较别扭,但一旦统一了,代码看起来是比较漂亮的。代码一致性也是美的一种。

关于函数式

函数式编程已经成了编程语言的必备特性,不光C++引入了,其他语言,比如Java等等都包含了某些函数式语言的特性。从某种程度上来说,函数式编程是趋势。比如,匿名函数在某些情况下是很方便的,避免每次都要去定义一些仅用一次的函数。

C++20可能要引入的concepts也来源于函数式编程语言,包括Rust的trait,都跟haskell的typeclass有关,一旦编译器支持了,对模板编程绝对是一大利好。

C++既然是多泛型语言,再多支持一个函数式,也就不奇怪了。

关于C++的替代语言

这方面,Rust和Go的呼声最高。在我看来,C++不会被替代,但Rust是一种比C++更好的选择,而Go可能是Java的替代。

简要说下两门语言的对比:Rust和Go的语言设计是两个方向,前者从学术化出发,兼顾实用化,后者从实用化出发,慢慢引入其他高级特性。
1.从整体上看,Rust语言要完整,后期出现坑的可能性要小,Go通过简单吸引了大量的开发者,在1.0版泛型都没有,而且异常处理极其单薄。从语言一致性上看,Rust较好。
2.从语言效率看,Rust跟C++都没有GC,速度相当;Go有Gc,速度是优于Java的,但离C++还有一段距离,而且这个距离很难再减了。

有一点要提,Go入门实在是太快了,稍微看一下语法,在ide里就可以写代码了;而Rust的所有权、borrow机制,尤其是生命期就拦住了不少人。

如果没有特殊需求,优选新语言,因为新语言历史包袱少,能剪掉很多学习成本。

关于C++的体量

这几年,C++加快了演进速度,越来越多的特性加入到了语言当中,相对地,C++做减法的速度却没快起来。这导致了一种结果,就是C++语法膨胀的太快了。而且C++还要兼容C语言,最后语言规范刷刷的涨。

关于对策,语言的标准我们是没有可操纵空间的,但我们可以选择自己的“个人标准”。如,你是做应用开发的,用到底层特性的可能性不大,这个时候,你就完全可以不用原始指针、不用宏、仅使用{}初始化。。。这样是完全可以的。

总结

现代C++是在进步的。后续文章开始写一些现代C++的语言或库的特性了,大部分都是老工具很好的替代。

请关注我的公众号哦。
352609696-5c1a6bc675f22_articlex

本文固定链接: http://www.js-code.com/c/c_61862.html