You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为C++20的connection_c概念定义更优雅灵活的读写接口?

问题描述

原始的C++20连接概念定义如下:

template <typename t>
concept connection_c = requires(t p_t) {
  requires std::copy_constructible<t>;

  {
    p_t.write(std::declval<const uint8_t *>(), std::declval<const uint8_t *>())
    } -> std::same_as<communication_status_t>;

  {
    p_t.read(std::declval<uint8_t *>(), std::declval<uint8_t *>(),
             std::declval<uint8_t **>())
    } -> std::same_as<communication_status_t>;
};

希望让write和read方法的定义更优雅灵活,避免显式依赖const uint8_t*或uint8_t*类型。

尝试过这些思路但未成功:

  • 给write/read定义模板参数,发现不可行;
  • 考虑用std::convertible_to<uint8_t>,但没掌握正确语法,也不确定是否适用;
  • 尝试迭代器相关概念(比如input_iterator、output_iterator),但不知道怎么实现或是否可行。

之后自己实现了两种改进方案:

第一种方案:

template <typename t, typename t_byte>
concept connection_c = requires(t p_t) {
  requires std::copy_constructible<t> ;

  { p_t.id() } -> std::same_as<tnctt::id>;

  {
    p_t.write(std::declval<const t_byte *>(), std::declval<const t_byte *>())
    } -> std::same_as<communication_status_t>;

  {
    p_t.read(std::declval<t_byte *>(), std::declval<t_byte *>(),
             std::declval<t_byte **>())
    } -> std::same_as<communication_status_t>;
};

第二种优化后的方案:

template <typename t>
concept one_byte_c = (sizeof(t) == 1);

template <typename t, typename t_byte>
concept connection_c = requires(t p_t) {
    requires std::copy_constructible<t> && std::move_constructible<t> &&
                 !std::default_initializable<t>;
       
    requires one_byte_c<t_byte>;    
   {
    p_t.write(std::declval<const t_byte *>(), std::declval<const t_byte *>())
    } -> std::same_as<communication_status_t>;

  {
    p_t.read(std::declval<t_byte *>(), std::declval<t_byte *>(),
             std::declval<t_byte **>())
    } -> std::same_as<communication_status_t>;
};

请问还有其他可行的实现方式吗?

可行的替代实现方式

1. 使用迭代器概念替代指针

直接利用C++20的迭代器概念,让write和read支持符合要求的迭代器类型,不局限于指针,既灵活又贴合标准库设计风格:

#include <iterator>

template <typename t>
concept connection_c = requires(t p_t) {
  requires std::copy_constructible<t>;

  // write接受输入迭代器范围
  {
    p_t.write(std::declval<std::input_iterator auto>(), 
              std::declval<std::input_iterator auto>())
  } -> std::same_as<communication_status_t>;

  // read接受输出迭代器和指向迭代器的指针(用于返回实际读取位置)
  {
    p_t.read(std::declval<std::output_iterator auto>(), 
             std::declval<std::output_iterator auto>(),
             std::declval<std::output_iterator auto*>())
  } -> std::same_as<communication_status_t>;
};

这种方式下,任何满足input_iterator的类型(比如const uint8_t*、std::vector<uint8_t>::const_iterator)都能传给write;read则接受output_iterator类型(比如uint8_t*、std::back_insert_iterator<std::vector<uint8_t>>),灵活性大幅提升。

2. 让概念自动推导字节类型

无需显式指定t_byte模板参数,让概念自动推导write/read方法的参数类型,同时约束该类型为单字节:

template <typename t>
concept connection_c = requires(t p_t) {
  requires std::copy_constructible<t> && std::move_constructible<t> &&
           !std::default_initializable<t>;

  // 推导write的参数类型并约束为单字节
  requires requires(const t& conn, const auto* first, const auto* last) {
    { conn.write(first, last) } -> std::same_as<communication_status_t>;
    requires sizeof(std::remove_const_t<decltype(*first)>) == 1;
  };

  // 推导read的参数类型并约束为单字节,同时保证输出指针类型匹配
  requires requires(t& conn, auto* first, auto* last, auto** out_last) {
    { conn.read(first, last, out_last) } -> std::same_as<communication_status_t>;
    requires sizeof(decltype(*first)) == 1;
    requires std::same_as<decltype(*out_last), decltype(first)>;
  };
};

这个版本不需要额外模板参数,概念会自动检查write和read的参数是否是指向单字节类型的指针,同时验证返回值符合要求。

3. 基于std::byte兼容其他单字节类型

优先使用std::byte作为基础类型,同时兼容其他单字节类型(比如uint8_t、int8_t),结合std::convertible_to和单字节约束:

#include <cstddef>

template <typename t>
concept connection_c = requires(t p_t) {
  requires std::copy_constructible<t> && std::move_constructible<t> &&
           !std::default_initializable<t>;

  // write接受指向可转换为std::byte的单字节类型的指针
  {
    p_t.write(std::declval<const std::convertible_to<std::byte> auto*>(), 
              std::declval<const std::convertible_to<std::byte> auto*>())
  } -> std::same_as<communication_status_t>;

  // read接受指向可转换为std::byte的单字节类型的指针
  {
    p_t.read(std::declval<std::convertible_to<std::byte> auto*>(), 
             std::declval<std::convertible_to<std::byte> auto*>(),
             std::declval<std::convertible_to<std::byte> auto**>())
  } -> std::same_as<communication_status_t>;
};

这种方式既保证类型的单字节特性,又利用std::convertible_to<std::byte>确保类型能和标准字节类型互操作。

内容的提问来源于stack exchange,提问作者canellas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:07:26