提供的内容讲的是 IPC(进程内通信)中图像通道提取的服务实现,并且使用 CCI(Contract-Concept-Implementation)模式组织软件。

1⃣ 术语解释


缩写 含义
IPC Intra-Process Communication,进程内通信,用于不同模块或线程间的数据交换
Programs 在受限环境下运行的软件(如嵌入式或实时系统)
CCI Contract-Concept-Implementation 模式
Contract 接口约束,定义服务和功能
Concept 功能抽象,提供逻辑和行为说明
Implementation 具体实现,包括数据结构和算法

2⃣ 问题定义:Channel Extraction

  1. 图片在不同应用中广泛使用
  2. 我们希望提取图片的颜色通道,例如 R/G/B 通道
  3. 提供一个服务接口,让客户端通过通信端点(IPC)调用通道提取功能

思路:

  • 输入:图像数据
  • 输出:分离的通道数据
  • 通信:使用 IPC(如 dbus)作为服务端和客户端的桥梁
    公式化表示:
  • 假设图像 III 大小为 H×W×3H \times W \times 3H×W×3(RGB三通道):
    I=R,G,B,R,G,B∈RH×W I = { R, G, B }, \quad R,G,B \in \mathbb{R}^{H \times W} I=R,G,B,R,G,BRH×W
  • 通道提取函数:
    f(I)=(R,G,B) f(I) = (R, G, B) f(I)=(R,G,B)

3⃣ 标准 IPC 实现(示例使用 sd-bus)

#include <systemd/sd-bus.h>
sd_bus_error error = SD_BUS_ERROR_NULL;   // 初始化错误对象
sd_bus_message *msg = NULL;               // 消息对象指针
sd_bus *bus = NULL;                        // IPC bus 对象
int32_t result;                            // 存储函数调用结果
const int r = 0;                            // 示例常量

注释:

  • sd_bus_error 用于捕获 dbus 错误
  • sd_bus_message 表示 IPC 消息
  • sd_bus 表示连接到 dbus 的总线
  • result 用于返回函数调用状态
  • r 是常量或索引,用于操作图像通道

3.1 数据流逻辑

  1. 客户端调用 IPC 服务请求提取通道
  2. 服务端通过 sd_bus 接收消息
  3. 调用图像通道提取函数
  4. 返回提取结果给客户端
    公式化:
    client→IPC msgserver→f(I)(R,G,B)→IPC msgclient \text{client} \xrightarrow{\text{IPC msg}} \text{server} \xrightarrow{f(I)} (R,G,B) \xrightarrow{\text{IPC msg}} \text{client} clientIPC msg serverf(I) (R,G,B)IPC msg client

3.2 Channel Extraction 核心算法(示例)

void extract_channels(uint8_t* image, int width, int height,
                      uint8_t* R, uint8_t* G, uint8_t* B) {
    for (int i = 0; i < width*height; ++i) {
        R[i] = image[3*i + 0];
        G[i] = image[3*i + 1];
        B[i] = image[3*i + 2];
    }
}

注释:

  • 输入 image 是线性 RGB 数据,大小为 width*height*3
  • 分别填充三个输出通道数组 R/G/B

4⃣ 总结

  • 使用 CCI 模式组织服务:
    1. Contract:定义通道提取接口
    2. Concept:说明如何分离 RGB 通道
    3. Implementation:基于 sd-bus 的 IPC 服务实现
  • IPC 数据流
    client request→sd-bus service→channel extraction→client response \text{client request} \rightarrow \text{sd-bus service} \rightarrow \text{channel extraction} \rightarrow \text{client response} client requestsd-bus servicechannel extractionclient response
  • 图像通道提取是线性遍历操作,适合在受限环境中实时执行

1⃣ 背景

  • 目标:通过 sd-bus 调用 IPC 服务提取图像通道
  • 文件路径和通道参数:
const char* file = "/home/sample";       // 原始图像路径
const char* h = "/home/modified";        // 修改后的路径
const uint8_t channel = 1;               // 要提取的通道
  • 调用 sd-bus 方法:
sd_bus_call_methodC(
    bus,
    "com.cppcon2024.Channel",           // 服务名
    "/com/cppcon2024/Channel",          // 对象路径
    "com.cppcon2024.Channel",           // 接口名
    "ExtractChannel",                   // 方法名
    &error, &m,                         // 错误对象和消息对象
    "ooy",                              // 参数类型:object path, object path, uint8
    file, h, channel                     // 参数值
);

注释:

  • "ooy" 表示方法参数类型:o = object path, y = byte(uint8)
  • 这是 标准 IPC 调用,同步调用 sd-bus 方法

2⃣ CCI 模式:Contract-Concept-Implementation

2.1 Contract(契约)

  • 契约定义类型或资源必须满足的条件
  • 例如 SD_BUS_CONTRACT 强制类型必须是特定的 std::unique_ptr
typedef std::unique_ptr<sd_bus, decltype(&sd_bus_unref)> SD_BUS_INNER_TYPE;
struct SD_BUS_CONTRACT {
    template<typename T>
    static constexpr bool IsUniquePtr = std::is_same<T, SD_BUS_INNER_TYPE>::value;
};

注释:

  • SD_BUS_INNER_TYPE:管理 sd_bus* 的智能指针,自动释放资源
  • IsUniquePtr:静态布尔值,用于类型检查

2.2 Concept(概念)

  • 概念用于约束模板参数,确保类型满足契约
  • C++20 的 concept 功能可以在编译期检查类型
template <typename T>
concept SD_BUS_CONCEPT = requires {
    requires SD_BUS_CONTRACT::IsUniquePtr<T>;
};

注释:

  • 模板参数 T 必须是 SD_BUS_CONTRACT 中定义的 SD_BUS_INNER_TYPE
  • 编译器会报错,如果类型不符合契约

2.3 Implementation(实现)

  • 实现是具体类型或函数,用于创建和操作契约类型
template<SD_BUS_CONCEPT T = SD_BUS_INNER_TYPE>
[[nodiscard]] T MAKE_SD_BUS() {
    return T(nullptr, &sd_bus_unref); // 创建智能指针,默认空指针
}
  • 使用结构体封装:
template<SD_BUS_CONCEPT T = SD_BUS_INNER_TYPE>
struct SD_BUS {
    T bus = MAKE_SD_BUS();                  // 内部智能指针
    decltype(bus.get()) ptr = bus.get();    // 获取原始指针
    decltype(bus.get())* addressof_ptr = &ptr;
    inline auto operator()() { return addressof_ptr; }        // 返回指针地址
    inline auto operator*() const { return ptr; }             // 解引用
};

注释:

  • bus 管理 sd_bus*,生命周期自动管理
  • operator()operator* 提供访问接口

2.4 Message 类型封装(SD_BUS_MESSAGE)

  • 同理,对 sd_bus_message 也可以封装:
typedef std::unique_ptr<sd_bus_message, decltype(&sd_bus_message_unref)> SD_BUS_MESSAGE_TYPE;
struct SD_BUS_MESSAGE_CONTRACT {
    template<typename T>
    static constexpr bool IsUniquePtr = std::is_same<T, SD_BUS_MESSAGE_TYPE>::value;
};
template <typename T>
concept SD_BUS_MESSAGE_CONCEPT = requires {
    requires SD_BUS_MESSAGE_CONTRACT::IsUniquePtr<T>;
};
template<SD_BUS_MESSAGE_CONCEPT T = SD_BUS_MESSAGE_TYPE>
[[nodiscard]] T MAKE_SD_BUS_MESSAGE() {
    return T(nullptr, &sd_bus_message_unref); // 创建智能指针
}

注释:

  • 同样使用智能指针封装消息,确保资源安全

3⃣ 总结

3.1 工作流程

  1. Contract(契约):定义必须满足的类型特征(如 unique_ptr 管理资源)
  2. Concept(概念):在编译期约束模板参数,确保类型符合契约
  3. Implementation(实现):创建对象、封装操作接口(如 MAKE_SD_BUS
    公式化:
    Implementation⊆Concept⊆Contract \text{Implementation} \subseteq \text{Concept} \subseteq \text{Contract} ImplementationConceptContract
  • Contract → Concept → Implementation
  • 确保 类型安全资源管理正确

3.2 优势

  • 自动管理 sd_bus / sd_bus_message 的生命周期
  • 编译期检查类型是否符合契约
  • 可扩展性强,便于定义不同类型的 IPC 资源

1⃣ SD_BUS_MESSAGE 封装

1.1 Implementation(实现)

template<SD_BUS_MESSAGE_CONCEPT T = SD_BUS_MESSAGE_TYPE>
struct SD_BUS_MESSAGE {
    T message = MAKE_SD_BUS_MESSAGE();          // 内部智能指针,自动管理资源
    decltype(message.get()) ptr = message.get(); // 获取原始指针
    decltype(message.get())* addressof_ptr = &ptr; // 指针地址
    inline auto operator()() const { return addressof_ptr; }  // 返回指针地址
    inline operator decltype(auto)() const { return ptr; }    // 解引用获取原始 sd_bus_message*
};

注释:

  • T 必须符合 SD_BUS_MESSAGE_CONCEPT
  • 内部 message 使用 std::unique_ptr 管理 sd_bus_message 生命周期
  • operator()operator decltype(auto) 提供访问接口

1.2 Concept(概念)

template<typename T>
concept SD_BUS_MESSAGE_CONCEPT =
    std::is_same<T, SD_BUS_MESSAGE<SD_BUS_MESSAGE_TYPE>>::value;

注释:

  • 确保模板参数类型是 SD_BUS_MESSAGE<SD_BUS_MESSAGE_TYPE>

2⃣ SD_BUS_ERROR_TYPE 封装

2.1 Contract(契约)

struct SD_BUS_ERROR_TYPE_CONTRACT {
    template<typename T, typename = int>
    static constexpr bool HasFunctionOperatorOverload = false;
    template<typename T>
    static constexpr bool HasFunctionOperatorOverload<
        T, decltype(&T::operator const char*, 0)
    > = true;
    template<typename T>
    static constexpr bool IsTriviallyConstructible = std::is_constructible<T>::value;
};

注释:

  • 确保 SD_BUS_ERROR_TYPE

    1. operator const char* 重载
    2. 可平凡构造

2.2 Concept(概念)

template <typename T>
concept SD_BUS_ERROR_TYPE_CONCEPT =
    requires { requires SD_BUS_ERROR_TYPE_CONTRACT::HasFunctionOperatorOverload<T>; } &&
    requires { requires SD_BUS_ERROR_TYPE_CONTRACT::IsTriviallyConstructible<T>; };

注释:

  • 编译期约束类型必须满足契约

2.3 Implementation(实现)

class SD_BUS_ERROR_TYPE {
public:
    operator const char*() const { return nullptr; }  // 返回错误描述
private:
    friend class SD_BUS_ERROR_TYPE_CONTRACT;
};

注释:

  • 提供 operator const char* 用于获取错误信息
  • 通过友元关系让 Contract 可以访问内部

3⃣ SD_BUS_ERROR_STRUCT 封装

3.1 Contract(契约)

class SD_BUS_ERROR_STRUCT_CONTRACT {
public:
    template <typename T, typename = int>
    static constexpr bool HasFieldName = false;
    template <typename T>
    static constexpr bool HasFieldName<T, decltype((void) T::name, 0)> = true;
    template<typename T>
    static constexpr bool IsTypeNameStr = std::is_same<decltype(T::name), std::string>::value;
    template <typename T, typename = int>
    static constexpr bool HasFieldDescription = false;
    template <typename T>
    static constexpr bool HasFieldDescription<T, decltype((void) T::description,0)> = true;
    template<typename T>
    static constexpr bool IsTypeDescriptionStr =
        std::is_same<decltype(T::description), std::string>::value;
};

注释:

  • 检查类型是否有 namedescription 字段
  • 确保字段类型是 std::string

3.2 Concept(概念)

template <typename T>
concept SD_BUS_ERROR_STRUCT_CONCEPT =
    requires {
        requires SD_BUS_ERROR_STRUCT_CONTRACT::HasFieldName<T>;
        requires SD_BUS_ERROR_STRUCT_CONTRACT::IsTypeNameStr<T>;
        requires SD_BUS_ERROR_STRUCT_CONTRACT::HasFieldDescription<T>;
        requires SD_BUS_ERROR_STRUCT_CONTRACT::IsTypeDescriptionStr<T>;
    };

注释:

  • 编译期检查类型是否满足 name/description 字段要求

3.3 Implementation(实现)

创建 sd_bus_error 结构
template <SD_BUS_ERROR_TYPE_CONCEPT T>
[[nodiscard("Return value must be placed inside variable")]]
constexpr auto make_sdbus_error_structure() {
    return (sd_bus_error){ .name = T{}, .message = T{}, ._need_free = int{} };
}

注释:

  • 返回一个 sd_bus_error 结构
  • 使用模板类型 T 初始化 name 和 message
  • _need_free 标志资源是否需要释放
封装错误结构体
template<SD_BUS_ERROR_TYPE_CONCEPT T = SD_BUS_ERROR_TYPE>
struct SD_BUS_ERROR_STRUCT_INNER {
    SD_BUS_ERROR_STRUCT_INNER() : name(""), description("") {}
    SD_BUS_ERROR_STRUCT_INNER(const std::string& name, const std::string& description)
        : name(std::move(name)), description(std::move(description)) {}
    virtual ~SD_BUS_ERROR_STRUCT_INNER() { sd_bus_error_free(&sd_bus_error); }
    std::string name;
    std::string description;
    sd_bus_error sd_bus_error = make_sdbus_error_structure<T>();
};

注释:

  • 构造函数可自定义 namedescription
  • 析构函数释放 sd_bus_error
  • 内部保持 sd_bus_error 与 CCI 类型安全绑定

4⃣ 总结

4.1 核心思路

  1. Contract(契约)
    • 定义必须存在的函数、字段、类型特征
    • 检查资源管理规则(如智能指针、可构造性)
  2. Concept(概念)
    • 在编译期约束模板参数
    • 确保类型满足 Contract
  3. Implementation(实现)
    • 提供实际类型、函数、资源管理
    • 自动管理生命周期(如 sd_bus_message_unref, sd_bus_error_free
      公式化表示:
      Implementation⊆Concept⊆Contract \text{Implementation} \subseteq \text{Concept} \subseteq \text{Contract} ImplementationConceptContract
  • Contract → Concept → Implementation
  • 通过智能指针和模板概念保证类型安全和资源管理

1⃣ SD_BUS_ERROR 封装

1.1 SD_BUS_ERROR_STRUCT 实现

template <SD_BUS_ERROR_STRUCT_CONCEPT T>
struct SD_BUS_ERROR_STRUCT {
    SD_BUS_ERROR_STRUCT() : t(T()) {}  // 默认构造内部错误结构
    SD_BUS_ERROR_STRUCT(const std::string& name, const std::string& description)
        : t(T(name, description)) {} // 使用 name/description 构造内部结构
    [[nodiscard("Overloaded operator-> returns inner instance of sd_bus_error.")]]
    auto operator->() { return &t.sd_bus_error; }  // 返回 sd_bus_error*,方便访问
    auto operator()() { return &t.sd_bus_error; }  // 可调用形式返回 sd_bus_error*
    T t;  // 内部存储的错误结构
};

注释:

  • t 是内部封装的 SD_BUS_ERROR_STRUCT_INNER 对象
  • operator->operator() 提供对底层 sd_bus_error 的访问
  • 使用模板概念约束类型安全

1.2 类型别名与概念

typedef SD_BUS_ERROR_STRUCT<SD_BUS_ERROR_STRUCT_INNER<>> SD_BUS_ERROR;
template<typename T>
concept SD_BUS_ERROR_CONCEPT = std::is_same<T, SD_BUS_ERROR>::value;

注释:

  • SD_BUS_ERROR_STRUCT_INNER<> 封装为默认 SD_BUS_ERROR 类型
  • 编译期检查类型是否为 SD_BUS_ERROR

2⃣ SERVICE_NAME 封装(服务名验证)

2.1 Contract(契约)

constexpr int SERVICE_NAME_MAX_LENGTH = 30;          // 服务名最大长度
constexpr const char* service_name_starts_with = "com";  // 服务名必须以 "com" 开头
struct SERVICE_NAME_CONTRACT {
    template<size_t T>
    constexpr static bool IsMaxLength = T < SERVICE_NAME_MAX_LENGTH;
    template<bool T>
    constexpr static bool StartsWith = T;
};

注释:

  • CONTRACT 定义服务名必须满足的条件

    1. 长度小于 30
    2. 前缀为 "com"

2.2 Contract 工具函数

// 检查长度
template<size_t N>
static constexpr size_t SERVICE_NAME_IS_MAX_LENGTH(const char (&str)[N]) {
    return N;
}
// 检查前缀
template<std::size_t N>
static constexpr auto SERVICE_NAME_STARTS_WITH(const char (&str)[N]) {
    auto subspan = std::span{str}.first(3);  // 取前三个字符
    int i = 0;
    for (auto const& elem : subspan)
        if (elem != service_name_starts_with[i++]) return false;
    return true;
}

注释:

  • SERVICE_NAME_IS_MAX_LENGTH 返回字符串长度
  • SERVICE_NAME_STARTS_WITH 检查是否以 "com" 开头

2.3 Concept(概念)

template<size_t T, bool U>
concept SERVICE_NAME_CONCEPT =
    requires { requires SERVICE_NAME_CONTRACT::IsMaxLength<T>; } &&
    requires { requires SERVICE_NAME_CONTRACT::StartsWith<U>; };

注释:

  • 模板参数 TU 分别对应长度和前缀检查
  • 编译期确保服务名满足 CONTRACT

2.4 Implementation(实现)

template<size_t T, bool U>
requires SERVICE_NAME_CONCEPT<T, U>
[[nodiscard]] constexpr auto SERVICE_NAME_INNER(const char (&str)[T]) {
    return SERVICE_NAME_TYPE{str};  // 返回封装的服务名类型
}
#define SERVICE_NAME(T) \
    SERVICE_NAME_INNER<SERVICE_NAME_IS_MAX_LENGTH(T), SERVICE_NAME_STARTS_WITH(T)>(T)

注释:

  • 使用宏 SERVICE_NAME(T) 快速创建经过编译期检查的服务名
  • SERVICE_NAME_TYPE 是封装的服务名类型(可进一步封装接口)

3⃣ 总结

3.1 核心逻辑

  1. SD_BUS_ERROR
    • Contract:检查结构和操作符
    • Concept:模板约束类型
    • Implementation:封装内部结构、提供访问 sd_bus_error 的操作符
  2. SERVICE_NAME
    • Contract:定义最大长度和前缀条件
    • Concept:模板约束编译期检查
    • Implementation:封装服务名,使用宏创建

3.2 公式化理解

  • 错误类型封装
    SD_BUS_ERROR=SD_BUS_ERROR_STRUCT⟨SD_BUS_ERROR_STRUCT_INNER⟩ \text{SD\_BUS\_ERROR} = \text{SD\_BUS\_ERROR\_STRUCT} \langle \text{SD\_BUS\_ERROR\_STRUCT\_INNER} \rangle SD_BUS_ERROR=SD_BUS_ERROR_STRUCTSD_BUS_ERROR_STRUCT_INNER
  • 服务名验证
    SERVICE_NAME⊆CONCEPT⊆CONTRACT,length<30,prefix="com" \text{SERVICE\_NAME} \subseteq \text{CONCEPT} \subseteq \text{CONTRACT}, \quad \text{length} < 30, \quad \text{prefix} = "com" SERVICE_NAMECONCEPTCONTRACT,length<30,prefix="com"

3.3 优势

  • 通过 CCI 模式,保证:
    1. 类型安全
    2. 资源自动管理(sd_bus_error、sd_bus_message)
    3. 编译期检查服务名合法性

1⃣ SERVICE_NAME 实现

template<size_t T, bool U>
requires SERVICE_NAME_CONCEPT<T, U>
[[nodiscard]] constexpr auto SERVICE_NAME_INNER(const char (&str)[T]) {
    return SERVICE_NAME_TYPE{str};  // 返回封装后的服务名对象
}
#define SERVICE_NAME(T) \
    SERVICE_NAME_INNER<SERVICE_NAME_IS_MAX_LENGTH(T), SERVICE_NAME_STARTS_WITH(T)>(T)
template<typename T>
concept SERVICE_NAME_TYPE_CONCEPT = std::is_same<T, SERVICE_NAME_TYPE>::value;

注释:

  • SERVICE_NAME(T) 用于编译期验证服务名
  • SERVICE_NAME_TYPE_CONCEPT 确保类型安全

2⃣ DBUS 类型封装

2.1 DBUS_PATH(对象路径)

struct DBUS_PATH {
    template<std::size_t N>
    constexpr explicit DBUS_PATH(const char (&value)[N]) : value(value) {}
    const char* value;             // 保存 D-Bus 对象路径
    std::string signature{"o"};    // D-Bus 类型签名 'o' 表示 object path
};

2.2 DBUS_UINT8(无符号 8 位整数)

struct DBUS_UINT8 {
    constexpr explicit DBUS_UINT8(uint8_t value) : value(value) {}
    uint8_t value;                  // 保存数值
    std::string signature{"y"};     // D-Bus 类型签名 'y' 表示 uint8
};

注释:

  • 这些封装用于 编译期类型检查
  • 每种类型包含 D-Bus 签名字符串,用于调用时拼接

3⃣ 支持类型概念

// 判断 T 是否属于列表 U 中的任意类型
template<typename T, typename... U>
concept AnyOf = (std::is_same<T, U>::value || ...);
// 检查所有参数都是 DBus 支持类型
template<typename... T>
concept DBusSupportedTypes = (AnyOf<T, DBUS_PATH, DBUS_UINT8> && ...);

注释:

  • DBusSupportedTypes 保证 SD_BUS_CALL_METHODC 的参数都是合法类型

4⃣ 常量定义(通道索引)

#define RED_CHANNEL   DBUS_UINT8{0}
#define GREEN_CHANNEL DBUS_UINT8{1}
#define BLUE_CHANNEL  DBUS_UINT8{2}

注释:

  • 用于选择图像通道
  • 方便调用时传递类型安全参数

5⃣ SD_BUS_CALL_METHODC 重构

5.1 函数模板定义

template<typename... DBUS_SUPPORTED_TYPES>
requires DBusSupportedTypes<DBUS_SUPPORTED_TYPES...>
[[nodiscard]] constexpr inline auto SD_BUS_CALL_METHODC(
    SD_BUS_TYPE_CONCEPT auto const& bus,
    SERVICE_NAME_TYPE_CONCEPT auto const& service_name,
    OBJECT_PATH_TYPE_CONCEPT auto const& object_path,
    INTERFACE_NAME_TYPE_CONCEPT auto const& interface_name,
    METHOD_NAME_CONCEPT auto const& method_name,
    SD_BUS_ERROR_CONCEPT auto& error,
    SD_BUS_MESSAGE_CONCEPT auto& m,
    DBUS_SUPPORTED_TYPES const&... args
);

注释:

  • bus:D-Bus 总线对象
  • service_name:服务名对象(编译期验证)
  • object_path:D-Bus 对象路径
  • interface_namemethod_name:D-Bus 接口和方法名
  • error:错误对象
  • m:消息对象
  • args:D-Bus 参数,保证类型安全

5.2 调用实现

sd_bus_call_methodC(
    bus,
    service_name.str,      // 服务名字符串
    object_path.str,       // 对象路径字符串
    interface_name.str,    // 接口名字符串
    method_name.str,       // 方法名字符串
    error(),
    m(),
    (Cargs.signature + ...).c_str(),  // 拼接参数签名
    args.value...                      // 展开参数值
);

注释:

  • (Cargs.signature + ...).c_str():将所有参数类型签名拼接成字符串
  • args.value...:展开传入的参数值
  • 编译期保证所有类型合法,运行时直接调用 sd_bus_call_methodC

6⃣ 总结

6.1 核心设计

  1. SERVICE_NAME:编译期验证服务名长度和前缀
  2. DBUS_PATH / DBUS_UINT8:封装 D-Bus 参数类型,包含类型签名
  3. DBusSupportedTypes:模板概念,保证函数模板参数合法
  4. SD_BUS_CALL_METHODC:类型安全、可扩展的 D-Bus 方法调用封装

6.2 公式化理解

  • 参数类型约束:
    args∈DBUS_PATH,DBUS_UINT8 \text{args} \in { \text{DBUS\_PATH}, \text{DBUS\_UINT8} } argsDBUS_PATH,DBUS_UINT8
  • D-Bus 调用模板:
    SD_BUS_CALL_METHODC(bus,service_name,object_path,interface,method,error,message,args…) \text{SD\_BUS\_CALL\_METHODC}(bus, service\_name, object\_path, interface, method, error, message, args\ldots) SD_BUS_CALL_METHODC(bus,service_name,object_path,interface,method,error,message,args)
  • 参数签名拼接:
    signature=∑iargsi.signature signature = \sum_{i} args_i.signature signature=iargsi.signature

6.3 优势

  • 编译期类型安全:避免传入错误类型
  • 自动拼接签名:简化 D-Bus 调用
  • 与 CCI 模式兼容:Contract → Concept → Implementation

1⃣ D-Bus 调用对比

1.1 传统调用

sd_bus_call_method(
    bus,
    service_name,
    object_path,
    interface_name,
    method_name,
    &error,
    &m,
    "ooy",       // 参数类型签名: object, object, uint8
    file,
    save_path,
    channel
);

注释:

  • 每次调用都要显式传入类型签名字符串 "ooy"
  • 参数是原始 C 类型,不保证类型安全
  • 汇编量大,因为所有参数和函数调用都保留

1.2 CCI 封装调用

sd_bus_call_method(
    bus,
    service_name,
    object_path,
    interface_name,
    method_name,
    error,
    m,
    DBUS_PATH{"/home/image/sample"},
    DBUS_PATH{"/home/image/red"},
    RED_CHANNEL
);

注释:

  • 使用类型安全的封装类型 DBUS_PATHDBUS_UINT8
  • 签名字符串由模板编译期自动拼接
  • 优化后生成的汇编非常简洁:
main:
    mov eax, 2
    ret

优势:

  1. 编译期类型检查
  2. 零运行开销
  3. 汇编量少(inline + constexpr)

2⃣ PERSON 类设计(使用 CCI 模式)

2.1 需求

  • 属性:name, surname, age, expenses
  • 每个属性有 getter
  • name 限制:
    • 长度最小 3,最大 40
    • 必须以 'A' 开头

2.2 辅助模板工具

逻辑非
template<bool T>
struct logical_not {
    static constexpr bool value = !T;
};
字段检查器
class FieldChecker {
public:
    template<typename T, typename Field>
    static constexpr bool HasField(Field field) {
        return std::is_member_object_pointer<decltype(field)>::value;
    }
    template<typename T, typename... Fields>
    static constexpr bool HasFields(Fields... field) {
        return (HasField<T>(field) && ...);  // 检查所有字段
    }
};
函数检查器
class FunctionChecker {
public:
    template<typename T, typename Function>
    static constexpr bool HasFunction(Function function) {
        return std::is_member_function_pointer<decltype(function)>::value;
    }
    template<typename T, typename... Functions>
    static constexpr bool HasFunctions(Functions... function) {
        return (HasFunction<T>(function) && ...);  // 检查所有方法
    }
};

注释:

  • 编译期检查类是否包含指定字段和成员函数

2.3 属性类型

struct NAME {
    template<std::size_t N>
    constexpr explicit NAME(const char (&name)[N]) : name(name) {}
    std::string name;
};
struct SURNAME {
    template<std::size_t N>
    constexpr explicit SURNAME(const char (&surname)[N]) : surname(surname) {}
    std::string surname;
};
struct AGE {
    constexpr explicit AGE(int age) : age(age) {}
    int age;
};
struct EXPENSES {
    constexpr explicit EXPENSES(double expenses) : expenses(expenses) {}
    double expenses;
};

注释:

  • 属性封装为独立类型
  • 支持编译期约束

2.4 PERSON Contract(契约)

template<typename T>
class PersonContract {
public:
    static constexpr bool FieldsExist =
        FieldChecker::HasFields<T>(&T::name, &T::surname, &T::age, &T::expenses);
    static constexpr bool FunctionsExist =
        FunctionChecker::HasFunctions<T>(&T::getName, &T::getSurname, &T::getAge, &T::getExpenses);
    static constexpr bool IsNotDefaultConstructible =
        logical_not<std::is_default_constructible<T>::value>::value;
};

注释:

  • CONTRACT 检查:

    1. 所有字段存在
    2. 所有 getter 存在
    3. 禁止默认构造

2.5 PERSON Concept(概念)

template<typename Person>
concept PersonConcept =
    PersonContract<Person>::FieldsExist &&
    PersonContract<Person>::FunctionsExist &&
    PersonContract<Person>::IsNotDefaultConstructible;

注释:

  • 编译期约束模板类型必须符合 CONTRACT

2.6 PERSON Name 类型检查

template<std::size_t N>
static constexpr bool IsMinLength = N > 3;
template<std::size_t N>
static constexpr bool IsMaxLength = N < 40;
template<std::size_t N>
static constexpr std::size_t Length(const char (&str)[N]) { return N; }
template<std::size_t N>
static constexpr bool StartsWith(const char (&str)[N]) { return str[0] == 'A'; }
template<std::size_t N, bool... U>
requires (U && ...)
[[nodiscard]] constexpr auto MAKE_NAME_OBJECT(const char(&str)[N]) { return NAME{str}; }

注释:

  • 编译期检查名字长度和首字母
  • MAKE_NAME_OBJECT 生成合法 NAME 对象

3⃣ 总结

3.1 核心优势

  1. 类型安全:字段、函数、长度、首字母全部在编译期检查
  2. 零运行开销:使用 constexpr 和模板元编程
  3. 可扩展:可添加更多属性类型,自动验证

3.2 公式化理解

  • 名字合法性:
    IsValidName(name)=(Length(name)>3)∧(Length(name)<40)∧(name[0]=′A′) \text{IsValidName}(name) = (\text{Length}(name) > 3) \wedge (\text{Length}(name) < 40) \wedge (name[0] = 'A') IsValidName(name)=(Length(name)>3)(Length(name)<40)(name[0]=A)
  • PERSON 类概念:
    PersonConcept(T)=HasFields(T)∧HasGetters(T)∧¬DefaultConstructible(T) \text{PersonConcept}(T) = \text{HasFields}(T) \wedge \text{HasGetters}(T) \wedge \neg \text{DefaultConstructible}(T) PersonConcept(T)=HasFields(T)HasGetters(T)¬DefaultConstructible(T)
  • CCI 模式:
    Contract⊆Concept⊆Implementation \text{Contract} \subseteq \text{Concept} \subseteq \text{Implementation} ContractConceptImplementation

1⃣ PERSON 类实现(使用 CCI)

1.1 名字辅助宏

#define MAKE_NAME(T) \
    MAKE_NAME_OBJECT<Length(T), IsMinLength<Length(T)>, IsMaxLength<Length(T)>, StartsWith(T)>(T)

注释:

  • 通过宏 MAKE_NAME(T) 快速生成经过 编译期验证NAME 对象

  • 检查:

    1. 长度合法(3 ≤ length ≤ 40)
    2. 首字母是 'A'

1.2 PERSON 类定义

struct Person {
    template<typename NAME, typename SURNAME, typename AGE, typename EXPENSES>
    requires PersonTypes::SupportedTypes<NAME, SURNAME, AGE, EXPENSES>
    Person(NAME name, SURNAME surname, AGE age, EXPENSES expenses)
        : name(name), surname(surname), age(age), expenses(expenses) {}
    NAME getName() { return name; }
    SURNAME getSurname() { return surname; }
    AGE getAge() const { return age; }
    EXPENSES getExpenses() { return expenses; }
    NAME name;
    SURNAME surname;
    AGE age;
    EXPENSES expenses;
    friend class PersonContract<Person>;  // Contract 可以访问私有成员
};

注释:

  • 构造函数模板保证所有属性类型符合 SupportedTypes
  • getter 方法保证访问安全
  • friend 允许 PersonContract 在编译期检查字段

1.3 main 函数示例

int main(int /* argc */, char** /* argv */) {
    Person person{
        MAKE_NAME("Arian"),            // 编译期验证名字
        SURNAME{"Ajdari"},             // 姓
        AGE{29},                       // 年龄
        EXPENSES{500.45}               // 消费
    };
    return 0;
}

注释:

  • MAKE_NAME("Arian") 编译期检查长度和首字母
  • 所有类型都经过模板约束和 Contract 验证
  • 最终生成的二进制与传统方法相比没有额外开销

2⃣ CCI 的总结理解

2.1 优势

  1. 编译期类型安全:部分逻辑从运行期转移到编译期
  2. 高层抽象封装低层设施:例如将 sd_bus 封装为安全、类型化接口
  3. Contract 可以表达软件文档或 UML 意图:可以作为程序化签名
  4. 零运行时开销:所有验证在编译期完成

2.2 注意事项

  1. CCI 不是万能工具,不必在所有地方使用
  2. CCI 功能也可以通过其他 C++ 技术实现
  3. 使用权在程序员手中,需要根据场景判断

3⃣ 公式化理解

3.1 名字合法性

IsValidName(name)=(Length(name)≥3)∧(Length(name)≤40)∧(name[0]=′A′) \text{IsValidName}(name) = (\text{Length}(name) \ge 3) \wedge (\text{Length}(name) \le 40) \wedge (name[0] = 'A') IsValidName(name)=(Length(name)3)(Length(name)40)(name[0]=A)

3.2 PERSON 类概念

PersonConcept(T)=FieldsExist(T)∧FunctionsExist(T)∧¬DefaultConstructible(T) \text{PersonConcept}(T) = \text{FieldsExist}(T) \wedge \text{FunctionsExist}(T) \wedge \neg \text{DefaultConstructible}(T) PersonConcept(T)=FieldsExist(T)FunctionsExist(T)¬DefaultConstructible(T)

3.3 CCI 模式公式

Contract⊆Concept⊆Implementation \text{Contract} \subseteq \text{Concept} \subseteq \text{Implementation} ContractConceptImplementation

注释:

  • Contract 定义规则
  • Concept 编译期约束
  • Implementation 真正实现功能
    总结
  • 使用 CCI,你可以在编译期确保类型和字段合法,减少运行时错误
  • 它适合封装 低层设施安全敏感接口
  • 最终生成的二进制效率高且类型安全
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐