C++ 实现基于模板的编译期依赖注入系统架构模式解析及其完整源码【源码】

小宇姑娘_1258

小宇姑娘_1258

2026-05-23

670人浏览

原创

纯编译期依赖注入本质是模板参数化的类型组合与静态多态展开,非运行时对象替换;它依赖std::tuple、requires约束和constexpr构造,拒绝反射与中心化容器。

c++ 实现基于模板的编译期依赖注入系统架构模式解析及其完整源码【源码】

纯编译期依赖注入在 C++ 里无法真正“注入”——它本质是类型组合与静态多态的编译期展开,不是运行时对象替换。你想要的,其实是 std::tuple + std::variant + 模板递归 + requires 约束构成的“依赖图构建器”,而非传统 DI 容器。

为什么不能照搬 Spring 或 Autofac 的思路?

C++ 没有反射、没有运行时类型擦除(除非手动加 std::any 或虚函数)、也没有中心化容器注册表。所谓“编译期 DI”,实际是:

  • 把依赖关系写成模板参数列表,例如 class ServiceA<dep1 dep2></dep1>
  • 用 constexpr 函数或 if constexpr 控制构造路径
  • 靠 SFINAE 或 C++20 requires 做接口契约检查,失败直接编译报错
  • 所有“注入点”必须在实例化时确定,无法延迟到 main() 之后

injector<t>::resolve<service>()</service></t> 这类调用根本不能存在

如果你看到某份代码里写了类似 injector.resolve<database>()</database>,那它要么用了宏模拟(不安全),要么底层偷偷用了 std::map<type_id std::function>></type_id>(已脱离编译期)。真编译期方案只接受:

template<typename db typename logger>
struct UserService {
    DB db;
    Logger logger;

    UserService(DB d, Logger l) : db(d), logger(l) {}
};
// 使用时:UserService<mockdb consolelogger> svc{MockDB{}, ConsoleLogger{}};
</mockdb></typename>

——所有类型和值都在模板实参和构造函数参数中显式写出,无隐式查找、无字符串名称、无运行时 map 查表。

一个可用的轻量级编译期依赖组装器(C++20)

核心目标:给定一组服务类型,自动推导依赖链并构造嵌套对象。关键限制是:每个服务必须定义 using deps = std::tuple<depa depb>;</depa> 和一个接受对应参数的构造函数。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

实操要点:

  • 用 std::tuple_cat 展开依赖元组,再用 std::make_from_tuple 构造服务
  • 依赖循环会触发无限模板实例化,需靠 static_assert(!std::is_same_v<t u>)</t> 在关键节点拦截
  • 避免使用 auto 返回类型推导,否则依赖链会丢失类型信息,导致后续 requires 判定失效
  • 示例节选(仅关键骨架):
template<typename service>
consteval auto make_service() {
    if constexpr (requires { Service::deps{}; }) {
        constexpr auto deps_tuple = Service::deps{};
        return Service{std::make_from_tuple<service>(deps_tuple)};
    } else {
        return Service{};
    }
}
</service></typename>

注意:consteval 强制编译期求值,但要求所有依赖类型也支持 consteval 构造 —— 很多标准库类型(如 std::string)不满足,此时只能退回到 constexpr + 运行时初始化。

最容易被忽略的硬伤:头文件爆炸与编译时间失控

每增加一个服务类型,就可能触发数十个模板实例化;依赖深度超过 4 层后,Clang/GCC 的错误信息会变成不可读的嵌套模板栈。真实项目中更可行的做法是:

  • 只对核心抽象层(如 Repository<t></t>、Handler<cmd></cmd>)做编译期组合
  • 具体实现(PostgresRepo、HttpHandler)用工厂函数返回 std::unique_ptr,保持运行时灵活性
  • 用 #include <concepts></concepts> 替代宏做约束,但别滥用 requires 嵌套,它会让编译器更难诊断

所谓“完整源码”,其实是一组可组合的类型契约 + 构造策略,而不是一个能直接 #include 就用的黑盒库。真要落地,得按你自己模块的生命周期和测试需求,一处处切开依赖、显式传参、放弃“自动发现”。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2248

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1019

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

447

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

327

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

426

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

600

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1409

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1217

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1325

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习