推荐使用sqlite_orm头文件库实现编译期自动映射:结构体需有默认构造函数、字段名与列名一致,调用make_storage和get_all即可返回填充好的std::vector;它零运行时反射、不依赖rtti,避免手动逐字段赋值导致的顺序错乱、类型不匹配和null静默截断问题。

SQL查询结果怎么映射到C++结构体?别手动赋值
不能直接绑定,C++标准库不提供SQL到struct的自动映射。必须借助第三方库或手写胶水代码。硬靠std::tuple或std::vector<:string></:string>逐字段取值再赋值,既易错又难维护——尤其字段顺序变动、类型不匹配、NULL处理时,segmentation fault或静默数据截断很常见。
推荐用SQLite3 + sqlite_orm(轻量且零运行时反射)
sqlite_orm是头文件-only库,编译期生成绑定逻辑,不依赖RTTI或宏魔术,适合嵌入式和性能敏感场景。它要求结构体满足:有默认构造函数、字段名与表列名一致(或用as_<code>重命名)、支持<code>operator==(可选)。
- 定义结构体时用
using namespace sqlite_orm;,然后声明struct User { int id; std::string name; }; - 建映射:
auto storage = make_storage("db.sqlite", make_table("users", make_column("id", &User::id), make_column("name", &User::name))); - 查数据:
auto users = storage.get_all<user>();</user>—— 返回std::vector<user></user>,字段自动按列顺序+类型匹配填充 - 注意:如果数据库列是
TEXT但C++字段是int,会在运行时报sqlite_orm::sqlite_error,不是静默失败
用ODBC或libpq时,如何避免手写10行取值代码?
ODBC和PostgreSQL的libpq只返回SQLCHAR*或PQgetvalue()字符串,必须自己转换。这时建议封装一个模板函数,而不是每张表都写一遍if (col == "age") user.age = std::stoi(row[2]);。
- 用
std::map<:string std::string></:string>先存列名→值映射,再按字段名索引取值,比按序号安全 - 对可空字段,检查
is_null标志(ODBC用SQLLEN*参数,libpq用PQgetisnull()),别直接调std::stoi - 日期时间字段最危险:
std::chrono::system_clock::time_point无法直转,得先解析成std::string再用std::get_time或第三方date::parse - 字段名大小写敏感:PostgreSQL默认小写,MySQL默认大小写不敏感,SQLite3取决于建表时写法——统一用小写字段名最省事
为什么不用ORM框架(如ODB或LiteSQL)?
ODB需要额外IDL文件和代码生成步骤,修改表结构就得重新跑odb命令;LiteSQL已多年未更新,对C++17支持弱。它们在大型项目里可能合适,但对单表CRUD为主的工具类程序,引入构建依赖和学习成本远高于收益。
真正容易被忽略的是NULL语义:SQL的NULL不等于C++的nullptr或默认值。哪怕结构体字段是int,数据库该列为NULL时,你拿到的可能是空字符串或全零字节——没做is_null检查就直接转换,结果就是脏数据入库或崩溃。这个检查点必须写死在每一层数据搬运逻辑里。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











