C++ 中文周刊 第117期

周刊项目地址

公众号

RSS https://github.com/wanghenshui/cppweeklynews/releases.atom

欢迎投稿,推荐或自荐文章/软件/资源等

提交 issue

感谢不语 赞助


资讯

标准委员会动态/ide/编译器信息放在这里

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2023-06-07 第205期

llvm weekly我可能也看一下,顺便展开讲讲。可能更新以后要挪到周六,周知一下

看内容多不多,不多就讲讲llvm weekly

另外视频压了很多没看。看视频最大的问题是关键信息提取太慢了,lighting talk能快一些,长视频突出一个铺垫拉满。

这周末我准备把2021的 lighting talk看一遍,周末可能发一下整理,或者下周发一下整理

文章

本周最热闹的应该是这个问题 DeepMind AI 创造出比人类快 70% 的排序算法,会产生哪些影响?

实际上根据他的压测结果,没有70%这个结论。有点收益,但不是70%

代码去年就合入了

review链接 https://reviews.llvm.org/D118029

代码链接 https://github.com/llvm/llvm-project/commit/194d1965d2c841fa81e107d19e27fae1467e7f11

这个问题下大家在互相拉扯,我之前看到这个也是先入为主嘲讽一波,啊原来汇编17行,你优化了一下,16行了,AI可以了,收收味

不能说没进步,首先不是introspect sort改成pdqsort这种跨步收益(llvm已经是pdqsort了。gcc不是,想用可以用boost)

其次看benchmark https://github.com/wanghenshui/cppweeklynews/pull/53

有些场景甚至慢了。但前排都是提升的,基本%1。

不过其他答案给了个AI优化hash算法的。这个确实牛逼 https://github.com/abseil/abseil-cpp/commit/74eee2aff683cc7dcd2dbaa69b2c654596d8024e

我一直觉得hash算法这玩意不是人想的,AI感觉在这个方向能有更大收获

依赖输入的AI优化说实话有点像PGO

优化尚不明显,AI仍需努力

话说问问ChatGPT老师也能得到相同的结论 https://zhuanlan.zhihu.com/p/635847068

之前聊过这个http://0x80.pl/notesen/2023-04-09-faster-parse-ipv4.html

Daniel Lemire他也感兴趣,毕竟他写了个url解析库ada 仓库 https://github.com/ada-url/ada

需要这玩意。他根据上面这哥们的代码改了一版本,相比gcc,性能提升十倍

代码

https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2023/06/08/src/sse_inet_aton.c

另外,文中提到的 simdzone 是dns zone文件解析库 代码 https://github.com/NLnetLabs/simdzone

说实话我一直没研究SIMD。感觉躲不开了。这里标记个TODO。早晚得研究下

一个很巧妙的办法让成员避免比较

比如一个类

struct A {
    using allocator_type = std::pmr::polymorphic_allocator<std::byte>;
    int data1;
    int data2;
    int data3;
    allocator_type alloc;
    A(int a, int b, int c, allocator_type d) : data1(a), data2(b), data3(c), alloc(d) {}
    friend auto operator<=>(const A&, const A&) = default;
};

怎么实现<=> 能不比较alloc呢?

像咱这种笨比,就手写,不default,写成里面的来比较

比如

friend std::strong_ordering operator<=>(const A& lhs, const A& rhs) {
  if (auto r = (lhs.data1 <=> rhs.data1); r != 0) {
    return r;
  } else if (auto r = (lhs.data2 <=> rhs.data2); r != 0) {
    return r;
  } else if (auto r = (lhs.data3 <=> rhs.data3); r != 0) {
    return r;
  } else {
    return (1 <=> 1);
  }
}

或者聪明一点,使用tie

friend std::strong_ordering operator<=>(const A& lhs, const A& rhs) {
  auto tie = [](auto& x) { return std::tie(x.data1, x.data2, x.data3); };
  return tie(lhs) <=> tie(rhs);
}
friend bool operator==(const A& lhs, const A& rhs) {
  auto tie = [](auto& x) { return std::tie(x.data1, x.data2, x.data3); };
  return tie(lhs) == tie(rhs);
}

但还是要手写,能不能default?

作者的办法

#include <compare>
#include <memory_resource>
#include <cassert>

struct ComparisonIgnorerBase {
    using CIB = ComparisonIgnorerBase;
    constexpr friend auto operator<=>(const CIB&, const CIB&) = default;
};

template<class T>
struct ComparisonIgnorer : ComparisonIgnorerBase {
    T t_;
    ComparisonIgnorer(T t) : t_(std::move(t)) {}
};

struct A {
    using allocator_type = std::pmr::polymorphic_allocator<std::byte>;
    int data1;
    int data2;
    int data3;
    ComparisonIgnorer<allocator_type> alloc;
    A(int a, int b, int c, allocator_type d) : data1(a), data2(b), data3(c), alloc(d) {}
    friend auto operator<=>(const A&, const A&) = default;
};

int main() {
    std::pmr::monotonic_buffer_resource mr1;
    std::pmr::monotonic_buffer_resource mr2;
    A a = {1,2,3, &mr1};
    A b = {1,2,3, &mr2};
    A c = {3,1,2, &mr1};
    assert(a == b);
    assert(a < c);
}

确实挺巧妙,不需要比较的成员,替他实现一个空的 <=> 鸠占鹊巢

看<程序员自我修养 链接装载库=""> 就行了。这个文章也是讲的那玩意

#include <span>

constexpr std::array a = {1, 2, 3, 4, 5};
constexpr std::span s{a};

static_assert(s[0]==a[0]);

看不懂

可读性问题,不是必要的operator() 不要用

struct StorageLoader
{
    template<typename DataType>
    DataType Load(StorageOptions<DataType> const* options);

    template<typename DataType>
    DataType operator()(StorageOptions<DataType> const* options)
    { return Load(options); }
};


// 1 Using function call operator
data1 = storageLoader(&data1Options);

// 2 Using named method
data1 = storageLoader.Load(&data1Options);

// 3 Named method works better for nullptr
data1 = storageLoader.Load<Data1>(nullptr);

第一种显然是不必要的

不必要的operator ()实现这玩意整花活没意义

repair_status repair::task_manager_module::get(int id) const {
    if (std::cmp_greater(id, _sequence_number)) {
        throw std::runtime_error(format("unknown repair id {}", id));
    }
    auto it = _status.find(id);
    if (it == _status.end()) {
        return repair_status::SUCCESSFUL;
    } else {
        return it->second;
    }
}

std::cmp_greater 是c++20的,之前介绍过,语义是

-1 > 0u; // true
std::cmp_greater(-1, 0u); // false

跟着最新标准演进代码,收益还是非常明显的,起码不会写错

浮点数的精度问题

视频

讲代码怎么写的,讲的挺好的 PPT在这里

https://github.com/mattgodbolt/correct-by-construction

感觉值得用中文讲一遍

想要演讲却不知道说啥?没有自信?这里有一堆指导视频教你做演讲

Andrei Alexandrescu的和Chandler Carruth 的演讲总是有意思,他们的演讲我一直都看。其他人说的哎也就那么回事

这个讲的是之前clang那个死循坏优化代码,UB介绍。已经介绍一万多遍了

介绍view的使用和一些bug,感觉之前说过类似的案例,比如range loop bug 迭代器边界问题等等。这个值得看一下,感觉今年cppcon还会讲一遍

开源项目需要人手

新项目介绍/版本更新

本文永久链接

如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账