版权所有 © 2016-2025 Antony Polukhin
根据 Boost 软件许可协议 1.0 版分发。(请参阅随附文件 LICENSE_1_0.txt 或在 https://boost.ac.cn/LICENSE_1_0.txt 复制)
目录
Boost.PFR 是一个 C++14 库,用于非常基础的反射。它可以让您通过索引访问结构元素,并为用户定义的类型提供其他类似于 std::tuple
的方法,而无需宏或样板代码
#include <iostream> #include <string> #include "boost/pfr.hpp" struct some_person { std::string name; unsigned birth_year; }; int main() { some_person val{"Edgar Allan Poe", 1809}; std::cout << boost::pfr::get<0>(val) // No macro! << " was born in " << boost::pfr::get<1>(val); // Works with any aggregate initializables! std::cout << boost::pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809} }
假设您正在编写数据库的包装库。根据 Boost.PFR 的使用情况,用户代码看起来会有所不同
不使用 Boost.PFR |
使用 Boost.PFR |
---|---|
#include <db/api.hpp> struct user_info { std::int64_t id; std::string name, email, login; }; user_info retrieve_friend(std::string_view name) { std::tuple info_tuple = db::one_row_as<std::int64_t, std::string, std::string, std::string>( "SELECT id, name, email, login FROM user_infos WHERE name=$0", name ); ///////////////////////////////////////////////////////////////////////////// user_info info { std::move(std::get<0>(info_tuple)), std::move(std::get<1>(info_tuple)), std::move(std::get<2>(info_tuple)), std::move(std::get<3>(info_tuple)), } ///////////////////////////////////////////////////////////////////////////// auto friend_info = ask_user_for_friend(std::move(info)); db::insert( "INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)", friend_info.id, ////////////////////////////////////////////////////// friend_info.name, // Users are forced to enumerate fields because your friend_info.email, // library can not iterate over the fields of a user friend_info.login // provided structure ); return friend_info; } |
#include <db/api.hpp> struct user_info { std::int64_t id; std::string name, email, login; }; user_info retrieve_friend(std::string_view name) { // With Boost.PFR you can put data directly into user provided structures user_info info = db::one_row_as<user_info>( "SELECT id, name, email, login FROM user_infos WHERE name=$0", name ); ////////////////// No boilerplate code to move data around ////////////////// ///////////////////////////////////////////////////////////////////////////// auto friend_info = ask_user_for_friend(std::move(info)); db::insert( "INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)", friend_info ///////////////////////////////////////////////////////// // Boost.PFR allows you to iterate over all the fields // of a user provided structure // ); return friend_info; } |
否则,您的库可能需要用户类型的自定义点
不使用 Boost.PFR |
使用 Boost.PFR |
---|---|
#include <db/api.hpp> struct user_info { std::int64_t id; std::string name, email, login; }; /// Customizations via hand-written code //////////////////////////////////////// auto db_api_tie(user_info& ui) noexcept { return std::tie(ui.id, ui.name, ui.email, ui.login); } auto db_api_tie(const user_info& ui) noexcept { return std::tie(ui.id, ui.name, ui.email, ui.login); } ///////////////////////////////////////////////////////////////////////////////// |
#include <db/api.hpp> struct user_info { std::int64_t id; std::string name, email, login; }; //////// With Boost.PFR there's no need in hand written customizations ////////// ///////////////////////////////////////////////////////////////////////////////// |
假设您正在编写序列化库。使用 Boost.PFR 序列化用户提供的结构(和嵌套结构)就像这样简单
void Write(Writer& writer, int value); void Write(Writer& writer, std::string_view value); template <typename T> std::enable_if_t<boost::pfr::is_implicitly_reflectable_v<T>> Write(Writer& writer, const T& value) { boost::pfr::for_each_field( value, [&writer](const auto& field) { Write(writer, field); }); }
使用 Boost.PFR,代码更短、更易读,并且编写起来更令人愉快。
![]() |
注意 |
---|---|
以上所有示例均受到 🐙 userver 框架中 Boost.PFR 用法的启发。 |
Boost.PFR 为可聚合初始化的结构添加了以下开箱即用的功能
std::tuple
协作的成员方法std::array
协作的成员名称方法Boost.PFR 是一个仅包含头文件的库,不依赖于 Boost。您可以将 “include” 文件夹的内容 从 Boost.PFR github 复制到您的项目中,该库就可以正常工作。对于没有 boost::
命名空间的库版本,请参阅 PFR。
![]() |
注意 |
---|---|
推荐的 C++ 标准是 C++20 及更高版本。C++17 对于不想访问结构成员名称的用户来说已经足够了。库至少需要 C++14!不支持 C++14 之前的编译器(C++11、C++03...) |