Boost Karma结构体元素输出顺序调整及无BOOST_FUSION_ADAPT_STRUCT实现问询
调整Boost Fusion生成器输出顺序 & 无ADAPT_STRUCT替代方案
看起来你是在用Boost Fusion遍历结构体成员并生成输出,默认顺序和BOOST_FUSION_ADAPT_STRUCT里的成员声明顺序一致,现在想调整输出顺序,同时找不用BOOST_FUSION_ADAPT_STRUCT的实现方式,我来一步步帮你解决:
一、修改输出顺序的几种方法
1. 直接调整BOOST_FUSION_ADAPT_STRUCT的成员顺序
这是最直接的方式——Fusion默认会按照你在ADAPT_STRUCT里声明的成员顺序遍历。假设你原来的代码是这样的:
struct MyStruct { int a3; int a2; int a1; }; BOOST_FUSION_ADAPT_STRUCT( MyStruct, (int, a3) (int, a2) (int, a1) )
那生成器自然会输出<3,2,1>。如果要得到<1,2,3>,只需要把ADAPT里的成员顺序改成结构体的自然顺序:
BOOST_FUSION_ADAPT_STRUCT( MyStruct, (int, a1) (int, a2) (int, a3) )
想要<2,1,3>就调整为:
BOOST_FUSION_ADAPT_STRUCT( MyStruct, (int, a2) (int, a1) (int, a3) )
2. 自定义遍历序列(不修改ADAPT_STRUCT)
如果不能改动原有的ADAPT_STRUCT定义,你可以手动构建一个包含成员指针的Fusion序列,按你想要的顺序遍历:
#include <boost/fusion/container/vector.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> #include <iostream> struct MyStruct { int a1 = 1; int a2 = 2; int a3 = 3; }; // 假设原ADAPT_STRUCT的顺序是a3,a2,a1,输出<3,2,1> BOOST_FUSION_ADAPT_STRUCT( MyStruct, (int, a3) (int, a2) (int, a1) ) int main() { MyStruct s; // 手动指定遍历顺序:a1,a2,a3 → 输出<1,2,3> auto custom_order = boost::fusion::make_vector( &MyStruct::a1, &MyStruct::a2, &MyStruct::a3 ); std::cout << "<"; bool first = true; boost::fusion::for_each(custom_order, [&](auto mem_ptr) { if (!first) std::cout << ", "; std::cout << s.*mem_ptr; first = false; }); std::cout << ">\n"; // 改成a2,a1,a3 → 输出<2,1,3> auto another_order = boost::fusion::make_vector( &MyStruct::a2, &MyStruct::a1, &MyStruct::a3 ); std::cout << "<"; first = true; boost::fusion::for_each(another_order, [&](auto mem_ptr) { if (!first) std::cout << ", "; std::cout << s.*mem_ptr; first = false; }); std::cout << ">\n"; return 0; }
二、不使用BOOST_FUSION_ADAPT_STRUCT的实现方式
1. C++17+ 结构化绑定 + std::apply
利用结构化绑定把结构体转换成tuple,再用std::apply遍历,完全不需要Boost Fusion:
#include <tuple> #include <iostream> #include <utility> struct MyStruct { int a1 = 1; int a2 = 2; int a3 = 3; }; // 自定义结构体转tuple的顺序 auto struct_to_tuple(const MyStruct& s) { // 这里可以任意调整成员顺序,比如要<2,1,3>就改成s.a2, s.a1, s.a3 return std::make_tuple(s.a1, s.a2, s.a3); } int main() { MyStruct s; auto t = struct_to_tuple(s); std::cout << "<"; // 用折叠表达式遍历tuple成员 std::apply([&](auto&&... args) { size_t count = 0; ((std::cout << (count++ ? ", " : "") << args), ...); }, t); std::cout << ">\n"; return 0; }
2. 使用Boost.PFR(编译期反射,无需ADAPT)
Boost.PFR(原Magic Get)是Boost库的一部分,支持无需手动adapt结构体,直接通过编译期反射获取成员:
#include <boost/pfr.hpp> #include <iostream> struct MyStruct { int a1 = 1; int a2 = 2; int a3 = 3; }; int main() { MyStruct s; // 按结构体声明顺序遍历输出<1,2,3> std::cout << "<"; boost::pfr::for_each_field(s, [&](auto&& val, size_t idx) { if (idx != 0) std::cout << ", "; std::cout << val; }); std::cout << ">\n"; // 自定义顺序输出<2,1,3> std::cout << "<" << boost::pfr::get<1>(s) << ", " << boost::pfr::get<0>(s) << ", " << boost::pfr::get<2>(s) << ">\n"; return 0; }
3. 手动编写遍历逻辑(简单场景)
如果结构体成员固定且数量不多,直接手动按顺序输出最直观,完全不需要任何库:
#include <iostream> struct MyStruct { int a1 = 1; int a2 = 2; int a3 = 3; }; void print_mystruct(const MyStruct& s) { // 直接按想要的顺序写就行 std::cout << "<" << s.a2 << ", " << s.a1 << ", " << s.a3 << ">\n"; } int main() { MyStruct s; print_mystruct(s); // 输出<2,1,3> return 0; }
内容的提问来源于stack exchange,提问作者Addy
相关产品推荐
相关产品推荐

