C++ 中文周刊 2024-05-19 第157期

周刊项目地址

公众号

qq群 点击进入

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

欢迎投稿,推荐或自荐文章/软件/资源等,评论区留言

本期文章由 HNY 赞助

最近内容很少,少到都没法凑出一篇。另外我自身状态也有问题,更新频率有点低

资讯

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

gcc 14.1发布

实现了很多c++23/26 特性,具体看链接吧

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2024-05-15 第254期

文章

An informal comparison of the three major implementations of std::string

三大编译器的string SSO实现细节有所差异,Raymoodchen做了一些汇编对比

伪代码大概这样

// gcc
struct string
{
    char* ptr;
    size_t size;
    union {
        size_t capacity;
        char buf[16];
    };

    bool is_large() { return ptr != buf; }
    auto data() { return ptr; }
    auto size() { return size; }
    auto capacity() { return is_large() ? capacity : 15; }
};

// msvc
struct string
{
    union {
        char* ptr;
        char buf[16];
    };
    size_t size;
    size_t capacity;

    bool is_large() { return capacity > 15; }
    auto data() { return is_large() ? ptr : buf; }
    auto size() { return size; }
    auto capacity() { return capacity; }
};

// clang
union string
{
    struct {
        size_t capacity;
        size_t size;
        char* ptr;
    } large;

    struct {
        unsigned char is_large:1;
        unsigned char size:7;
        char buf[sizeof(large) - 1];
    } small;

    bool is_large() { return small.is_large; }
    auto data() { return is_large() ? large.ptr : small.buf; }
    auto size() { return is_large() ? large.size : small.size; }
    auto capacity() { return is_large() ? large.capacity : sizeof(large) - 2; }
};

汇编比较不贴了,直接放结论

  gcc msvc clang
is_large slower faster faster
data() fast slower slower
size() fast fast much slower
empty() fast fast much slower³
capacity() slowest fast slower
32-bit size 24 24 12
64-bit size 32 32 24
32-bit SSO capacity 15 15 11
64-bit SSO capacity 15 15 22
ABI supports mixed state? yes no yes
implementation uses mixed state no forbidden no
Static initialization relocation no relocation no relocation

Pulling a single item from a C++ parameter pack by its index

假设你有一个变长参数,想访问某一个,怎么搞

template<int index, typename...Args>
void example(Args&&... args){
    // how do I access the index'th args parameter?
}

显而易见可以用tie



template<int index, typename...Args>
void example(Args&&... args)
{
    auto& arg = std::get<index>(
        std::tie(args...));
}

右值引用tie出来是左值引用。如果需要完美转发怎么办呢?用forward_as_tuple

template<int index, typename...Args>
void example(Args&&... args)
{
    auto&& arg = std::get<index>(
        std::forward_as_tuple(
            std::forward<Args>(args)...));
/*
    // The hard way
    using Arg = std::tuple_element_t<index,
        std::tuple<Args&&...>>;

    // The lazy way
    using Arg = decltype(arg);
*/
} 

感觉不熟悉api?好消息,c++26有变参模版解包

template<int index, typename...Args>
void example(Args&&... args)
{
    // 左值
    auto& arg = args...[index];
    using Arg = Args...[index];

    // 纯右
    auto&& arg = (Args...[index]&&)args...[index];
    using Arg = Args...[index]&&;
}

Why can’t I find the injected name of a templated class’s templated base class?

代码编译不过

template<typename T>
struct Base
{
    Base(T value);
};

template<typename T>
struct Derived : Base<T>
{
    Derived(T value) : Base(value) {}
};

为什么Derived看不到Base??需要手动using一下

using Base = typename Derived::Base;

Understanding AddressSanitizer: Better memory safety for your code

手把手教你熟悉Asan

一个typelist实现

为什么2024了还要typelist?作者给的需求是限定类型在一个子集内,比如序列化

template<typename... Types>
struct typelist {

  static consteval bool unique()
  {
    auto unroll = [](auto head, auto... tail) {
      if constexpr (sizeof...(tail) == 0) {
        return true;
      } else {
        using tail_list = typelist<decltype(tail)...>;
        auto head_in_tail = tail_list::template includes<decltype(head)>();
        auto tail_unique = typelist<decltype(tail)...>::unique();
        return !head_in_tail && tail_unique;
      }
    };
    return unroll(Types{}...);
  }


  template<typename T>
  static consteval bool includes() {
    return std::disjunction<std::is_same<T, Types>...>::value;
  }
};

视频

cpp weekly generator

一个不需要协程的generator实现

#include <utility>
#include <iostream>
#include <ranges>

auto generator(auto func) {
    return std::views::iota(0) | std::views::transform(func);
}

int main() {
    auto fib =  [i=0, j=1] (auto) mutable {
        return i = std::exchange(j, i+j);
    };
    for (auto v : generator(fib) | std::views::take(10)) {
        std::cout << v << " ";
    }
}

godbolt 挺妙的,range也不是一无是处哈

当然 range-v3有类似的玩意 views::generate_n

看测试代码 长得差不多的

用generator就更简单了

#include <utility>
#include <iostream>
#include <ranges>

#include <generator>

std::generator<int> fib() {
    int i = 0;
    int j = 1;
    while (true) {
        co_yield i = std::exchange(j, i+j);
    }

}

int main() {
    for (auto v : fib() | std::views::take(10)) {
        std::cout << v << " ";
    }
}

godbolt

Throwing tools on ranges

对比了几种循环代码,并cachegrind一下,火焰图一下。看个乐只能说

reflection in c++26

还没看,感觉有点东西

开源项目介绍

互动环节

唉 最近熬夜刷手机成瘾,感觉真有一种瘾

已经把什么微博小红书虎扑抖音卸载了。看帖子傻乐一看时间凌晨两点我靠

最近反思更新的内容,发现其实碎片不系统的知识很容易变成孔乙己卖弄,但读者到底喜欢什么,很难说

系统化的知识可能不是本周刊的初衷 但过于碎片并不能让人有读完感觉我靠学到了好牛能用上很爽的感觉

可能笔者还需要去找深度的内容来发,菜少一点不要紧但是得是硬菜

上一期

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