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

C++模块转型:公私代码分离的目录结构与最佳实践咨询

C++ Modules 公私代码分离与目录结构实践方案

背景

我采用Pitchfork目录布局:

project/
├─ src/
├─ include/

其中src/与include/为镜像结构(根据头文件是否需要公开调整):

project/
├─ include/
│  ├─ common/
│  │  ├─ language.h
│  │  ├─ settings.h
├─ src/
│  ├─ common/
│  │  ├─ settings.cpp
│  │  ├─ error.h
│  │  ├─ file.h
│  │  ├─ language.cpp
│  ├─ flow/
│  │  ├─ flow.cpp
│  │  ├─ flow.h
│  ├─ main.cpp

include/是公开目录,部署时对外暴露,src/则不对外公开。项目仅将include/和src/作为包含目录,比如代码中用#include "common/language.h"。

现在我正从传统头文件转向C++ Modules,需要理清公私代码的分离方式,以及如何在目录结构上体现这种分离:

  • 想设置project.common模块,但该模块部分内容对外公开(language、settings),部分仅项目内部使用(error、file)
  • 希望模块既能被外部应用使用,也能满足项目内部的代码依赖需求
  • 不想像传统头文件那样依赖大型聚合头,保持按需使用的灵活性

可行方案与最佳实践

1. 拆分模块:公共子模块 + 内部子模块

把原有的project.common拆分为两个独立模块,明确区分公私边界:

  • project.common:仅包含对外公开的内容(对应原include/common/下的文件)
  • project.common.internal:包含项目内部使用的私有内容(对应原src/common/下的error.h、file.h等)

调整后的目录结构:

project/
├─ modules/
│  ├─ common/
│  │  ├─ module.modulemap  # 定义project.common模块
│  │  ├─ language.cppm
│  │  ├─ settings.cppm
│  ├─ common_internal/
│  │  ├─ module.modulemap  # 定义project.common.internal模块
│  │  ├─ error.cppm
│  │  ├─ file.cppm
├─ src/
│  ├─ flow/
│  │  ├─ flow.cppm
│  │  ├─ module.modulemap
│  ├─ main.cpp
├─ include/  # 按需保留,用于兼容传统头文件场景
│  ├─ common/
│  │  ├─ language.h
│  │  ├─ settings.h

模块定义示例:

  • modules/common/module.modulemap:
module project.common {
    export module project.common.language;
    export module project.common.settings;
}

module project.common.language {
    export namespace project::common::language {
        // 公开接口声明
    }
}

module project.common.settings {
    export namespace project::common::settings {
        // 公开接口声明
    }
}
  • modules/common_internal/module.modulemap:
module project.common.internal {
    export module project.common.internal.error;
    export module project.common.internal.file;
    import project.common; // 内部模块可直接依赖公开模块
}

module project.common.internal.error {
    export namespace project::common::internal::error {
        // 内部错误处理接口
    }
}

优势:

  • 外部使用者只能访问project.common,完全隔离内部实现
  • 内部代码可同时导入两个模块,按需使用公私内容
  • 目录结构与模块边界一一对应,可读性强

2. 单模块分区:同一模块内区分公私接口

如果不想拆分模块,可利用C++ Modules的模块分区(Module Partitions),在同一个project.common内划分公开和内部区域:

目录结构:

project/
├─ modules/
│  ├─ common/
│  │  ├─ module.modulemap
│  │  ├─ common_public.cppm  # 公开分区入口
│  │  ├─ common_internal.cppm # 内部分区入口
│  │  ├─ language.cppm
│  │  ├─ settings.cppm
│  │  ├─ error.cppm
│  │  ├─ file.cppm
├─ src/
│  ├─ flow/
│  │  ├─ flow.cppm
│  ├─ main.cpp

模块定义示例:

module project.common {
    // 公开分区:对外导出
    export partition project.common.public;
    // 内部分区:仅内部可见,不对外export
    partition project.common.internal;
}

// 公开分区聚合公开子模块
module project.common : public {
    import :language;
    import :settings;
    export :language;
    export :settings;
}

module project.common : language {
    export namespace project::common::language {
        // 公开接口
    }
}

module project.common : settings {
    export namespace project::common::settings {
        // 公开接口
    }
}

// 内部分区聚合内部子模块
module project.common : internal {
    import :error;
    import :file;
    import :public; // 内部可访问公开内容
    export :error;
    export :file;
}

module project.common : error {
    export namespace project::common::error {
        // 内部接口
    }
}

使用方式:

  • 外部代码:import project.common; 仅能获取公开的language和settings接口
  • 内部代码:import project.common:internal; 可获取所有内部接口,同时访问公开内容

优势:

  • 保持单模块的聚合概念,符合原有的common逻辑
  • 通过分区明确公私边界,无需额外拆分模块

3. 兼容传统头文件的过渡方案

如果需要同时支持传统头文件和Modules,可在include/下保留公开头文件,将其作为模块接口的转发层:

比如include/common/language.h:

export module project.common.language;
export namespace project::common::language {
    // 接口声明与模块实现一致
}

模块实现文件modules/common/language.cppm:

module project.common.language;
// 接口具体实现

优势:

  • 支持逐步迁移,既兼容旧代码的#include,也支持新代码的import
  • 无需大幅调整现有目录结构

核心原则

  • 边界清晰:严格区分公私内容,避免外部代码意外访问内部实现
  • 按需导出:拆分细粒度的子模块或分区,避免大模块导致的冗余依赖
  • 结构对应:目录结构与模块结构保持一致,降低代码查找成本

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:40:21