C++ 中文周刊 第139期

周刊项目地址

公众号

qq群 手机qq点击进入

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

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

提交 issue

最近在找工作准备面试题,更新可能有些拖沓,见谅

本周内容比较少

本期文章由 Amnesia Captain 黄亮 Anein Jerry 赞助


资讯

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

编译器信息最新动态推荐关注hellogcc公众号 OSDT Weekly 2023-11-22 第229期

boost 有个scope库正在评审中 https://lastique.github.io/scope/libs/scope/doc/html/scope/scope_guards.html

简单来说又是个scope guard

文章

还是coroutine介绍。懂得可以跳过了

// simpleCoroutine.cpp

#include <coroutine>
#include <iostream>

struct MyCoroutine {                             // (1)
    struct promise_type {
        MyCoroutine get_return_object() {
            return std::coroutine_handle<promise_type>::from_promise(*this);
        }
        std::suspend_always initial_suspend() {
            return {};
        }
        std::suspend_always final_suspend() noexcept {
            return {};
        }
        void return_void() {}
        void unhandled_exception() {}
    };
    MyCoroutine(std::coroutine_handle<promise_type> handle): handle{handle} {}
    
    void resume() { 
        handle.resume(); 
    }
    void destroy() { 
        handle.destroy(); 
    }
    
    std::coroutine_handle<promise_type> handle;
};

MyCoroutine simpleCoroutine() {                      // (2)
    std::cout << "Start coroutine\n";
    co_await std::suspend_always{};
    std::cout << "Resume coroutine\n";
}

int main() {
    MyCoroutine coro = simpleCoroutine();
    std::cout << "Coroutine is not executed yet\n";
    coro.resume();
    std::cout << "Suspend coroutine\n";
    coro.resume();
    coro.destroy();
    return 0;
}

实际上是这样的

MyCoroutine simpleCoroutine() {
    MyCoroutine::promise_type p();
    MyCoroutine coro_obj = p.get_return_object();

    try {
      co_await p.inital_suspend();
      std::cout << "Start coroutine\n";
      co_await std::suspend_always{};
      std::cout << "Resume coroutine\n";
    } catch(...) {
      p.unhandled_exception();
    }
    co_await p.final_suspend();
}

理解Awaitable,suspend_always就是内建的一个简单awaitable

struct suspend_always {
    constexpr bool await_ready() const noexcept { return false; }
    constexpr void await_suspend(coroutine_handle<>) const noexcept {}
    constexpr void await_resume() const noexcept {}
};

co_await suspend_always 相当于

auto&& awaiter = std::suspend_always{};
  if(!awaiter.await_ready()) {
    awaiter.await_suspend(std::coroutine_handle<>...);
    //<suspend/resume>
  }
awaiter.await_resume();

这样最重要的co_await功能大概你就明白了

好了,来点复杂的

#include <coroutine>
#include <iostream>
#include <queue>


struct Task {

  struct promise_type {
    std::suspend_always initial_suspend() noexcept { return {}; }
    std::suspend_always final_suspend() noexcept { return {}; }

    Task get_return_object() { 
        return std::coroutine_handle<promise_type>::from_promise(*this); 
    }
    void return_void() {}
    void unhandled_exception() {}
  };

  Task(std::coroutine_handle<promise_type> handle): handle{handle} {}

  auto get_handle() { return handle; }

  std::coroutine_handle<promise_type> handle;
};

class Scheduler {

  std::queue<std::coroutine_handle<>> _tasks;

  public: 

    void emplace(std::coroutine_handle<> task) {
      _tasks.push(task);
    }

    void schedule() {
      while(!_tasks.empty()) {
        auto task = _tasks.front();
        _tasks.pop();
        task.resume();

        if(!task.done()) { 
          _tasks.push(task);
        }
        else {
          task.destroy();
        }
      }
    }

    auto suspend() {
      return std::suspend_always{};
    }
};


Task TaskA(Scheduler& sch) {
  std::cout << "Hello from TaskA\n";
  co_await sch.suspend();
  std::cout << "Executing the TaskA\n";
  co_await sch.suspend();
  std::cout << "TaskA is finished\n";
}

Task TaskB(Scheduler& sch) {
  std::cout << "Hello from TaskB\n";
  co_await sch.suspend();
  std::cout << "Executing the TaskB\n";
  co_await sch.suspend();
  std::cout << "TaskB is finished\n";
}


int main() {
  std::cout << '\n';
  Scheduler sch;
  sch.emplace(TaskA(sch).get_handle());
  sch.emplace(TaskB(sch).get_handle());
  std::cout << "Start scheduling...\n";
  sch.schedule();
  std::cout << '\n';
}

可以了。你已经入门了。 接下来可以看seastar代码了

或者先看这个 https://github.com/andreasbuhr/cppcoro

简单玩法

 struct Color {
    uint8_t r{ 0 };
    uint8_t g{ 0 };
    uint8_t b{ 0 };
};
template <>
struct std::formatter<Color> {
    constexpr auto parse(std::format_parse_context& ctx) {
        return ctx.begin();
    }

    auto format(const Color& col, std::format_context& ctx) const {
        return std::format_to(ctx.out(), "({}, {}, {})", col.r, col.g, col.b);
    }
};

恐怖玩法

template <>
struct std::formatter<Color> : std::formatter<string_view> {
    auto format(const Color& col, std::format_context& ctx) const {
        std::string temp;
        std::format_to(std::back_inserter(temp), "({}, {}, {})", 
                       col.r, col.g, col.b);
        return std::formatter<string_view>::format(temp, ctx);
    }
};

满头大汗玩法

template <>
struct std::formatter<Color> {
    constexpr auto parse(std::format_parse_context& ctx){
        auto pos = ctx.begin();
        while (pos != ctx.end() && *pos != '}') {
            if (*pos == 'h' || *pos == 'H')
                isHex_ = true;
            ++pos;
        }
        return pos;  // expect `}` at this position, otherwise, 
                      // it's error! exception!
    }

    auto format(const Color& col, std::format_context& ctx) const {
        if (isHex_) {
            uint32_t val = col.r << 16 | col.g << 8 | col.b;
            return std::format_to(ctx.out(), "#{:x}", val);
        }
        
        return std::format_to(ctx.out(), "({}, {}, {})", col.r, col.g, col.b);
    }

    bool isHex_{ false };
};

// std::cout << std::format("col {}\n", Color{ 100, 200, 255 });
// std::cout << std::format("col {:h}\n", Color{ 100, 200, 255 });
// col (100, 200, 255)
// col #64c8ff

c++和编译器结合太深了。但有些知识并不是都知道,导致错误触发未定义行为

这个基本上是去年cppcon的总结,挺好的。值得看看

这个pfr magic_get希望大家都掌握。起码嘴了十几次了

patchelf实践还是比较少见的。挺有意思

#include <iostream>
#include <string>

struct S {
    int m_num;
    std::string m_text;
};

int main() {
    S s{42};
    std::cout << "s.m_num: " << s.m_num << ", s.m_text: " << s.m_text << '\n';
}

这种构造有字段没初始化,加告警-Wmissing-field-initializers

开源项目介绍

最近进展,发现 cmpxchg16b 不该用。竟然比mutex还慢,还在研究

简单说就是你的文件更改了 触发inotify 然后 回调一下make

这可比cling简单多了

又一个embed库。std::embed还没影呢,凑活用的东西

感觉很快,但没有和sonic-cpp的对比。我本来想比一下

我折腾了半天sonic-cpp编译。ubuntu 2204 zen4. 各种编不过。放弃了我靠

跑了glaze自带的压测

比yyjson快。性能不错,和simdjson也有一拼。另外就是还用上了最新反射技术。实践挺深的

数据贴这里,感兴趣的自己看吧

招聘

无锡编译期HPC AI创业 需要会LLVM gcc的 https://mp.weixin.qq.com/s/qkwjICB_fzzMJErXmbKBBw

互动环节

哎,再也不喝冰美式。一宿没睡着我靠

之前收集了一波读者投票,关于周更其余实践插一些别的内容

重点在代码介绍代码走读。这里搞点素材给大家逼逼两句。类似lighting talk,5页10页ppt

另外也收集收集大家的其他意见以及投稿。能投稿广告收益都给你。咱们公众号每篇文章稳定收益7块,加个鸡腿没啥问题

本周内容不多啊,还是希望大家多多互动

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