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

如何使用boost::sml库从多层嵌套状态机获取当前状态?

解决Boost SML嵌套状态机当前状态名称获取问题

我们实现了三层嵌套的状态转移表Ts1(Ts2(Ts3)),使用visit_current_states方法时,仅能正确获取顶层Ts1的当前状态名称;当状态机进入Ts2或Ts3后,输出的是boost::ext::sml::v1_1_6::back::sm<...>类型字符串,而非对应状态名称。需要找到能正确获取各层级嵌套状态机当前状态的方案。

示例代码

#include <boost/sml.hpp>
#include <iostream>
using namespace boost::sml;

struct Start {};
struct GoNested {};

struct Ts3 {
    auto operator()() {
        return make_transition_table(
                *"nested_s3"_s + event<Start> = "Ts3_1"_s,
                "nested_s3"_s + boost::sml::on_entry<_> / [] { std::puts("---- nested_s3 ----"); },
                "Ts3_1"_s + boost::sml::on_entry<_> / [] { std::puts("---- Ts3_1 ----"); }
                );
    }
};
struct Ts2 {
    auto operator()() {
        return make_transition_table(
                *"nested_s2"_s + event<Start> = "Ts2_1"_s,
                "Ts2_1"_s + event<GoNested> = state<Ts3>,
                "nested_s2"_s + boost::sml::on_entry<_> / [] { std::puts("---- nested_s2 ----"); },
                "Ts2_1"_s + boost::sml::on_entry<_> / [] { std::puts("---- Ts2_1 ----"); });
    }
};
struct Ts1 {
    auto operator()() {
        return make_transition_table(
                *"s1"_s + event<Start> = "s2"_s,
                "s2"_s + event<GoNested> = state<Ts2>,
                "s1"_s + boost::sml::on_entry<_> / [] { std::puts("---- s1 ----"); },
                "s2"_s + boost::sml::on_entry<_> / [] { std::puts("---- s2 ----"); }
                );
    }
};

int main() {
    boost::sml::sm<Ts1, Ts2, Ts3> sMachine_;

    auto print = [&] {
        auto vis = [](auto state) { std::cout << "Current state = " << state.c_str() << std::endl; };
        sMachine_.visit_current_states(vis);
    };

    print(); sMachine_.process_event(Start{});
    print(); sMachine_.process_event(GoNested{});
    print(); sMachine_.process_event(Start{});
    print(); sMachine_.process_event(GoNested{});
    print(); sMachine_.process_event(Start{});
    print();
}

原运行输出

---- s1 ----
Current state = s1
---- s2 ----
Current state = s2
---- nested_s2 ----
Current state = boost::ext::sml::v1_1_6::back::sm<boost::ext::sml::v1_1_6::back::sm_policy<Ts2> >
---- Ts2_1 ----
Current state = boost::ext::sml::v1_1_6::back::sm<boost::ext::sml::v1_1_6::back::sm_policy<Ts2> >
---- nested_s3 ----
Current state = boost::ext::sml::v1_1_6::back::sm<boost::ext::sml::v1_1_6::back::sm_policy<Ts2> >
---- Ts3_1 ----
Current state = boost::ext::sml::v1_1_6::back::sm<boost::ext::sml::v1_1_6::back::sm_policy<Ts2> >

解决方案

问题核心是visit_current_states默认只遍历顶层状态,遇到嵌套子状态机时需递归访问其内部状态。我们可以通过编译期类型判断,识别子状态机对象并递归调用其visit_current_states方法。

修改后的main函数代码:

int main() {
    boost::sml::sm<Ts1, Ts2, Ts3> sMachine_;

    // 递归访问状态的lambda,支持处理子状态机
    auto recursive_visit = [](auto&& self, auto state) -> void {
        // 编译期判断是否为子状态机类型
        if constexpr (requires { state.visit_current_states(self); }) {
            state.visit_current_states(self);
        } else {
            std::cout << "Current state = " << state.c_str() << std::endl;
        }
    };

    auto print = [&] {
        sMachine_.visit_current_states(recursive_visit);
    };

    print(); sMachine_.process_event(Start{});
    print(); sMachine_.process_event(GoNested{});
    print(); sMachine_.process_event(Start{});
    print(); sMachine_.process_event(GoNested{});
    print(); sMachine_.process_event(Start{});
    print();
}

修改后运行输出

---- s1 ----
Current state = s1
---- s2 ----
Current state = s2
---- nested_s2 ----
Current state = nested_s2
---- Ts2_1 ----
Current state = Ts2_1
---- nested_s3 ----
Current state = nested_s3
---- Ts3_1 ----
Current state = Ts3_1

说明

  • 利用if constexpr进行编译期类型检查,判断当前状态是否具备visit_current_states方法(即是否为子状态机)
  • 若为子状态机,递归调用其visit_current_states,传入自身作为访问器
  • 若为普通状态,直接输出状态名称字符串

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 04:30:08