目录

1.简介

2.安装与集成

3.快速入门

4.完整示例

5.优势与适用场景


1.简介

        continuable 是一个专注于 异步操作延续(continuation) 的现代 C++ 开源库,旨在简化异步编程流程,解决 “回调地狱” 问题,提供直观、灵活的异步操作链式调用和组合能力。它的设计理念类似于 JavaScript 中的 Promise,但更贴合 C++ 语法特性和现代标准(C++11 及以上)。

        异步编程中,多个依赖的异步操作(如网络请求、文件 IO)常导致嵌套回调(“回调地狱”),代码可读性和维护性极差。continuable 通过 延续传递风格(Continuation-Passing Style) 封装异步操作,允许将异步操作的 “后续处理逻辑”(延续)通过链式调用串联,使异步流程更接近同步代码的线性结构。

        主要特性有:

  1. 链式延续:通过 then() 方法串联异步操作,前一个操作的结果自动传递给下一个延续。
  2. 错误处理:统一的错误传播机制,通过 catch_() 捕获链中任意环节的错误。
  3. 操作组合:支持并行(when_all())、串行(when_seq())等方式组合多个异步操作。
  4. 多范式兼容:可与回调函数、std::future、协程(C++20)等多种异步模型集成。
  5. 轻量级:header-only 库(仅需包含头文件),无外部依赖,易于集成。
  6. 类型安全:通过模板推导自动处理参数类型,编译期检查类型匹配。

2.安装与集成

continuable 是 header-only 库,无需编译,只需:

1.从 GitHub 仓库 下载源码或从网站下载压缩包。

https://github.com/Naios/continuable

2.将 include 目录添加到项目包含路径。

3.包含核心头文件 #include "continuable/continuable.hpp" 即可使用。

支持 C++11 及以上标准,兼容主流编译器(GCC、Clang、MSVC)。

注意:continuable依赖asio和function2库

asio库源码的下载地址:

Downloading Asio

function2的引用可参考:

function2:一个专注于函数对象包装的现代 C++ 开源库-CSDN博客

3.快速入门

1.通过make_continuable创建一个可延续对象,该对象在调用时会返回一个承诺

auto http_request(std::string url) {return cti::make_continuable<std::string>([url = std::move(url)](auto&& promise) {// Perform the actual request through a different library,// resolve the promise upon completion of the task.promise.set_value("<html> ... </html>");// or: promise.set_exception(std::make_exception_ptr(std::exception("Some error")));// or: promise.set_canceled();});
}auto mysql_query(std::string query) {return cti::make_continuable<result_set, bool>([url = std::move(url)](auto&& promise) {//                         ^^^^^^^^^^^^^^ multiple result types});
}auto do_sth() {return cti::make_continuable<void>([](auto&& promise) {//                         ^^^^ no result at all});
}auto run_it() {return async([] {// Directly start with a handler});
}continuable<> run_it() { // With type erasurereturn async([] {});
}

2.通过then附加您的延续,支持多个结果和部分处理程序:

mysql_query("SELECT `id`, `name` FROM `users`").then([](result_set users) {// Return the next continuable to process ...return mysql_query("SELECT `id` name FROM `sessions`");}).then([](result_set sessions) {// ... or pass multiple values to the next callback using tuples or pairs ...return std::make_tuple(std::move(sessions), true);}).then([](result_set sessions, bool is_ok) {// ... or pass a single value to the next callback ...return 10;}).then([](auto value) {//     ^^^^ Templated callbacks are possible too})// ... you may even pass continuables to the `then` method directly:.then(mysql_query("SELECT * `statistics`")).then([](result_set result) {// ...return "Hi";}).then([] /*(std::string result) */ { // Handlers can accept a partial set of arguments{// ...});

3.通过failnext处理故障:

http_request("example.com").then([] {throw std::exception("Some error");}).fail([] (std::exception_ptr ptr) {if (ptr) {try {std::rethrow_exception(ptr);} catch(std::exception const& e) {// Handle the exception or error code here}}});

4.通过特定的执行器调度延续(可能在不同的线程上或稍后)

auto executor = [](auto&& work) {// Dispatch the work here, store it for later invocation or move it to another thread.std::forward<decltype(work)>(work)();
};read_file("entries.csv").then([](Buffer buffer) {// ...}, executor);
//   ^^^^^^^^

5.通过when_allwhen_anywhen_seq连接可延续对象:

// `all` of connections:
(http_request("github.com") && http_request("example.com") && http_request("wikipedia.org")).then([](std::string github, std::string example, std::string wikipedia) {// The callback is called with the response of github,// example and wikipedia.});// `any` of connections:
(http_request("github.com") || http_request("example.com") || http_request("wikipedia.org")).then([](std::string github_or_example_or_wikipedia) {// The callback is called with the first response of either github,// example or wikipedia.});// `sequence` of connections:
(http_request("github.com") >> http_request("example.com") >> http_request("wikipedia.org")).then([](std::string github, std::string example, std::string wikipedia) {// The requests are invoked sequentially});// Mixed logical connections:
(http_request("github.com") && (http_request("example.com") || http_request("wikipedia.org"))).then([](std::string github, std::string example_or_wikipedia) {// The callback is called with the response of github for sure// and the second parameter represents the response of example or wikipedia.});// There are helper functions for connecting continuables:
auto all = cti::when_all(http_request("github.com"), http_request("example.com"));
auto any = cti::when_any(http_request("github.com"), http_request("example.com"));
auto seq = cti::when_seq(http_request("github.com"), http_request("example.com"));

6.通过result处理多个结果变量,并通过recover从故障中恢复:

make_exceptional_continuable<void>(std::make_exception_ptr(std::exception("Some error")).fail([] (std::exception_ptr ptr) {return recover();}).then([] () -> result<> {// We recovered from the failure and proceeding normally// Will yield a default constructed exception type to signal cancellationreturn cancel();});

7.对现有代码进行“promisify”处理,或使用(asio)完成令牌集成:

// Promisification of your existing code that accepts callbacks
auto async_resolve(std::string host, std::string service) {return cti::promisify<asio::ip::udp::resolver::iterator>::from([&](auto&&... args) {resolver_.async_resolve(std::forward<decltype(args)>(args)...);},std::move(host), std::move(service));
}// (boost) asio completion token integration
asio::io_context io_context;
asio::steady_timer steady_timer(io_context);steady_timer.expires_after(std::chrono::seconds(5));
steady_timer.async_wait(cti::use_continuable).then([] {// Is called after 5s});

4.完整示例

continuable 是一个 header-only 库(仅需包含头文件,无需编译库本身),因此使用 CMake 配置项目时,只需指定头文件路径和 C++ 标准即可。以下是详细的 CMake 配置步骤和示例:

1.假设项目结构如下(将 continuable 作为第三方库放在项目中):

2.CMakeLists.txt 配置

核心配置包括:指定 C++ 标准(需 C++11 及以上)、添加 continuable 的头文件路径。

# 最低CMake版本要求
cmake_minimum_required(VERSION 3.10)# 项目名称和版本
project(continuable_demo VERSION 1.0)# 指定C++标准(continuable需要C++11及以上)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # 禁用编译器扩展# 添加continuable的头文件路径
# 假设continuable放在third_party目录下
#target_include_directories(continuable_demo
#  PRIVATE
#    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/continuable/include
#)message(STATUS "continuable directories: ${CMAKE_CURRENT_SOURCE_DIR}")include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/include${CMAKE_CURRENT_SOURCE_DIR}/third_party/include/dep/function2/include
)# 添加源文件
add_executable(continuable_demosrc/main.cpp
)

3.示例代码(src/main.cpp)

编写一个简单的异步操作示例,验证配置是否正确:

#include <iostream>
#include <thread>
#include <chrono>
// 引入continuable头文件
#include "continuable/continuable.hpp"// 模拟异步操作:1秒后返回一个整数
auto async_operation(int value) {return cti::make_continuable<int>([value](auto&& promise) {// 在新线程中执行异步操作std::thread([value, promise = std::forward<decltype(promise)>(promise)]() mutable {std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时操作promise.set_value(value * 2); // 异步操作结果}).detach();});
}int main() {std::cout << "开始异步操作..." << std::endl;// 链式调用异步操作async_operation(5).then([](int result) {std::cout << "第一步结果: " << result << "(5*2)" << std::endl;return async_operation(result); // 传递结果到下一个异步操作}).then([](int result) {std::cout << "第二步结果: " << result << "(10*2)" << std::endl;})/*.catch_([](const std::exception& e) {std::cerr << "错误: " << e.what() << std::endl;})*/;// 等待异步操作完成(实际项目中用事件循环替代)std::this_thread::sleep_for(std::chrono::seconds(3));return 0;
}

4.编译步骤

mkdir build && cd build
cmake ..          # 生成Makefile
cmake --build . --config Debug             # 编译项目
.\Debug\continuable_demo # 运行程序

5.关键说明

1)header-only 特性

continuable 无需编译为静态库或动态库,只需在 CMake 中通过 target_include_directories 指定其头文件路径即可。

2)C++ 标准

必须指定 CMAKE_CXX_STANDARD 11 或更高(如 C++14、C++17),否则会因语法不兼容导致编译错误。

3)跨平台兼容性

上述配置兼容 Windows(MSVC)、Linux(GCC/Clang)、macOS,只需确保编译器支持 C++11 及以上标准。

6.完整源码下载地址

通过网盘分享的文件:continuableTest.zip
链接: https://pan.baidu.com/s/1MkrlvYChgIWr2boGnwD4_g?pwd=1234 提取码: 1234

5.优势与适用场景

  • 简化异步流程:将嵌套回调转为线性链式调用,代码更易读、维护。
  • 灵活组合:支持串行、并行等复杂异步工作流,满足多任务依赖场景。
  • 现代 C++ 友好:充分利用模板、lambda、移动语义等特性,类型安全且高效。

适用于需要处理大量异步操作的场景:网络编程(如 HTTP 请求、RPC 调用)、文件 IO、异步数据库操作等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/93013.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/93013.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/93013.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32--寄存器与标准库函数--通用定时器--输出比较(PWM生成)

目录 前言 通用定时器类型 向上计数、向下计数、中心对齐 输入捕获与输出比较概念 输出比较典型例子&#xff1a;驱动舵机旋转 通用定时器的输出比较库函数 代码 通用定时器的输出比较寄存器操作 代码 这里提供数据手册的寄存器 后言 前言 使用平台:STM32F407ZET6 使…

91、23种设计模式

设计模式是软件设计中反复出现的解决方案的模板&#xff0c;用于解决特定问题并提高代码的可维护性、可扩展性和可复用性。23种经典设计模式可分为创建型、结构型和行为型三大类&#xff0c;以下是具体分类及模式概述&#xff1a; 一、创建型模式&#xff08;5种&#xff09; 关…

力扣(串联所有单词的子串)

串联所有单词的子串问题&#xff1a;多滑动窗口与哈希表的实战应用。 一、题目分析&#xff08;一&#xff09;问题定义 给定字符串 s 和字符串数组 words&#xff08;words 中所有单词长度相同 &#xff09;&#xff0c;找出 s 中所有“串联子串”的起始索引。串联子串指包含 …

RH134 管理基本存储知识点

1. 对 Linux 磁盘进行分区时有哪两种方案&#xff1f;分别加以详细说明。答&#xff1a;MBR分区&#xff1a;主引导记录(MBR)分区方案是运行BIOS固件的系统上的标准方案。此方案支持最 多四个主分区。在Linux系统上&#xff0c;您可以使用扩展分区和逻辑分区来创建最多…

【JS 异步】告别回调地狱:Async/Await 和 Promise 的优雅实践与错误处理

【JS 异步】告别回调地狱&#xff1a;Async/Await 和 Promise 的优雅实践与错误处理 所属专栏&#xff1a; 《前端小技巧集合&#xff1a;让你的代码更优雅高效 上一篇&#xff1a; 【JS 数组】数组操作的“瑞士军刀”&#xff1a;精通 Array.reduce() 的骚操作 作者&#xff…

23.Linux : ftp服务及配置详解

Linux &#xff1a; ftp服务及配置详解 FTP 基本概念 定义&#xff1a;文件传输协议&#xff08;File Transfer Protocol&#xff09;&#xff0c;采用 C/S 模式工作。端口&#xff1a; 控制端口&#xff1a;21数据端口&#xff1a;20FTP 工作原理模式工作流程连接发起方主动模…

悲观锁乐观锁与事务注解在项目实战中的应用场景及详细解析

在今天做的项目练习部分中真的学到了很多东西&#xff0c;也补充了许多之前遗漏或是忘记的知识点&#xff0c;但时间精力有限&#xff0c;我就先记录一下今天用到的一个新东西&#xff0c;悲观锁和乐观锁。首先给出实际应用背景&#xff1a;在加入锁和事务注解之前&#xff0c;…

Java构造器与工厂模式(静态工程方法)详解

1. 构造器1.1 构造器的核心意义1.1.1 对象初始化构造器在创建对象 (new) 时自动调用, 用于初始化对象的状态 (如设置字段初始值, 分配资源等)无构造器时: 字段为默认值&#xff08;0/null/false&#xff09;有构造器&#xff1a;确保对象创建后即处于有效状态1.1.2 强制初始化…

解决jdk初始化运行,防火墙通信选错专业网络问题

问题描述新项目添加不同版本的jdk&#xff0c;运行时提示防火墙通信策略&#xff0c;选成专用网络。其他人访问后端接口时&#xff0c;提示连接失败。 解决方案&#xff1a;1、在搜索栏中输入 防火墙关键字&#xff0c;选择到防火墙和网络保护2、选择允许应用通过防火墙3、先点…

【Linux】常用命令(三)

【Linux】常用命令&#xff08;三&#xff09;1. export1.1 原理1.2 常用语法1.3 示例1.4 书中对命令的解释1.5 生效范围2. 测试服务地址与其端口能否访问2.1 nc(Netcat)命令2.2 telnet2.3 nmap2.4 curl命令 (适用于HTTP/HTTPS 服务)1. export export 是 Linux Shell&#xff…

Pytest项目_day15(yaml)

YAMLYAML是一个对所有编程语言都很友好的数据序列化标准&#xff0c;它是一种直观的能够被电脑识别的数据序列化格式&#xff0c;是一种可读性高且容易被人类阅读的脚本语言YAML语言的本质是一种通用的数据串行化格式适用场景 可以直接序列化为数组、字典解析成本低专门写配置文…

审批流程系统设计与实现:状态驱动、灵活扩展的企业级解决方案

审批流程系统设计与实现&#xff1a;状态驱动、灵活扩展的企业级解决方案 本文基于实际企业级审批系统源码&#xff0c;深入解析如何设计高扩展性、强一致性的审批流程引擎&#xff0c;涵盖状态机设计、多租户隔离、文件服务集成等核心实现。 1. 系统设计概览 审批系统的核心架…

汽车免拆诊断案例 | 2010款奥迪A4L车行驶中发动机偶尔自动熄火

故障现象 一辆2010款奥迪A4L车&#xff0c;搭载CDZ发动机 &#xff0c;累计行驶里程约为18.2万km。该车行驶中发动机偶尔自动熄火&#xff0c;有时熄火后能够立即重新起动着机&#xff0c;有时需要等待一会儿才能重新起动着机&#xff0c;故障频率较低。因该故障在其他维修厂陆…

Liam ERD:自动生成美观的交互式实体关系图

Liam ERD 是一个可以快速生成美观且具有交互性的数据库实体关系图&#xff08;ERD&#xff09;的工具&#xff0c;可以帮助用户实现复杂数据库结构的可视化。 Liam ERD 是一个免费开源的项目&#xff0c;代码托管在 GitHub&#xff1a; https://github.com/liam-hq/liam 功能…

网络协议序列化工具Protobuf

目录前言一、下载注意二、解压安装三、Protobuf的使用1、创建.proto文件2、利用protoc编译.proto文件前言 Protocol Buffers是Google的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法&#xff0c;它可⽤于&#xff08;数据&#xff09;通信协议、数据存储等。 Protoco…

从表单校验到API网关:全链路输入安全防护指南

从表单校验到 API 网关:全链路输入安全防护指南 在软件系统的安全防御体系中,输入安全是第一道防线,而这道防线的坚固程度直接决定了系统抵御外部攻击的能力。从用户在浏览器中填写表单的那一刻起,到数据经过 API 网关流转至后端服务,每一个环节都可能成为输入攻击的突破…

Flask vs Django:微框架与一站式对决

Flask 简介 1、简介 Flask诞生于2010年&#xff0c;是Armin ronacher用Python语言基于Werkzeug工具箱编写的轻量级Web开发框架&#xff0c;又称之为微框架。 "微"的含义&#xff1a;Flask旨在保持核心简洁&#xff0c;本身相当于内核&#xff0c;其他功能需通过扩展…

真实业务场景:mysql慢查询优化(从17秒的查询优化到700毫秒)

慢查询业务场景:原先在我们系统中要统计一些人员的单位 部门信息的数据情况&#xff0c;比如总的男女人数&#xff0c;每个单位下的男女人数等等&#xff0c;然后原来的sql是这样写的 根据一个单位的id 然后对一张表做出多个子查询进行查询&#xff0c;这时候统计记录 由于加载…

远程影音访问:通过 cpolar 内网穿透服务使用 LibreTV

文章目录前言【视频教程】1.关于LibreTV2.docker部署LibreTV3.简单使用LibreTV4.安装cpolar内网穿透5.配置ward公网地址6.配置固定公网地址总结LibreTV 与 cpolar 的协同应用&#xff0c;为用户打造了一条通往高清观影自由的便捷之路。通过这一方案&#xff0c;用户不仅摆脱了商…

Apache ECharts 6 核心技术解密 – Vue3企业级可视化实战指南

简介 ECharts 是百度开源的一个使用 JavaScript 实现的开源可视化库&#xff0c;它能够生动、可交互地展示数据。在 Vue3 项目中集成 ECharts 可以让你的项目更加直观和动态地呈现数据信息。 核心优势 特性SVG渲染器Canvas渲染器缩放保真度★★★★★★★☆☆☆动态交互性能…