C++ Boost MetaStateMachine定義狀態(tài)機(jī)超詳細(xì)講解
一、說明
Boost.MetaStateMachine 用于定義狀態(tài)機(jī)。狀態(tài)機(jī)通過對(duì)象的狀態(tài)來描述對(duì)象。它們描述了存在哪些狀態(tài)以及狀態(tài)之間可能存在哪些轉(zhuǎn)換。
Boost.MetaStateMachine 提供了三種不同的方式來定義狀態(tài)機(jī)。創(chuàng)建狀態(tài)機(jī)所需編寫的代碼取決于前端。
如果使用基本前端或函數(shù)前端,則可以用常規(guī)方式定義狀態(tài)機(jī):創(chuàng)建類,從 Boost.MetaStateMachine 提供的其他類派生它們,定義所需的成員變量,并編寫所需的 C++自己編碼?;厩岸撕秃瘮?shù)前端的根本區(qū)別在于,基本前端需要函數(shù)指針,而函數(shù)前端讓你使用函數(shù)對(duì)象。
第三個(gè)前端稱為 eUML,它基于特定領(lǐng)域的語言。該前端可以通過重用 UML 狀態(tài)機(jī)的定義來定義狀態(tài)機(jī)。熟悉 UML 的開發(fā)人員可以將 UML 行為圖中的定義復(fù)制到 C++ 代碼。您不需要將 UML 定義轉(zhuǎn)換為 C++ 代碼。
eUML 基于您必須與此前端一起使用的一組宏。宏的優(yōu)點(diǎn)是您不需要直接使用 Boost.MetaStateMachine 提供的許多類。您只需要知道要使用哪些宏。這意味著您不能忘記從類派生狀態(tài)機(jī),這可能發(fā)生在基本前端或函數(shù)前端。本章介紹使用 eUML 的 Boost.MetaStateMachine。
二、示例和代碼
示例 68.1。使用 eUML 的簡(jiǎn)單狀態(tài)機(jī)
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/state_grammar.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <iostream>
namespace msm = boost::msm;
using namespace boost::msm::front::euml;
BOOST_MSM_EUML_STATE((), Off)
BOOST_MSM_EUML_STATE((), On)
BOOST_MSM_EUML_EVENT(press)
BOOST_MSM_EUML_TRANSITION_TABLE((
Off + press == On,
On + press == Off
), light_transition_table)
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(
(light_transition_table, init_ << Off),
light_state_machine)
int main()
{
msm::back::state_machine<light_state_machine> light;
std::cout << *light.current_state() << '\n';
light.process_event(press);
std::cout << *light.current_state() << '\n';
light.process_event(press);
std::cout << *light.current_state() << '\n';
}示例 68.1 使用了最簡(jiǎn)單的狀態(tài)機(jī):一盞燈恰好有兩種狀態(tài)。它可以打開或關(guān)閉。如果它是關(guān)閉的,它可以被打開。如果已打開,則可以將其關(guān)閉??梢詮拿總€(gè)狀態(tài)切換到每個(gè)其他狀態(tài)。
示例 68.1 使用 eUML 前端來描述燈的狀態(tài)機(jī)。 Boost.MetaStateMachine 沒有主頭文件。因此,必須將需要的頭文件一一包含進(jìn)來。 boost/msm/front/euml/euml.hpp 和 boost/msm/front/euml/state_grammar.hpp 提供對(duì) eUML 宏的訪問。 boost/msm/back/state_machine.hpp 需要將前端的狀態(tài)機(jī)鏈接到后端的狀態(tài)機(jī)。雖然前端提供了定義狀態(tài)機(jī)的各種可能性,但狀態(tài)機(jī)的實(shí)際實(shí)現(xiàn)是在后端找到的。由于 Boost.MetaStateMachine 僅包含一個(gè)后端,因此您無需選擇實(shí)現(xiàn)。
Boost.MetaStateMachine 中的所有定義都在命名空間 boost::msm 中。不幸的是,許多 eUML 宏并沒有明確引用這個(gè)命名空間中的類。他們使用命名空間 msm 或根本不使用命名空間。這就是為什么示例 68.1 為命名空間 boost::msm 創(chuàng)建了一個(gè)別名,并使 boost::msm::front::euml 中的定義可用于 using 指令。否則 eUML 宏會(huì)導(dǎo)致編譯器錯(cuò)誤。
要使用燈的狀態(tài)機(jī),首先要定義關(guān)和開的狀態(tài)。狀態(tài)是用宏 BOOST_MSM_EUML_STATE 定義的,它需要狀態(tài)的名稱作為它的第二個(gè)參數(shù)。第一個(gè)參數(shù)描述狀態(tài)。稍后你會(huì)看到這些描述是什么樣子的。示例 68.1 中定義的兩個(gè)狀態(tài)稱為關(guān)閉和打開。
要在狀態(tài)之間切換,需要事件。事件是用宏 BOOST_MSM_EUML_EVENT 定義的,它期望事件的名稱作為其唯一參數(shù)。示例 68.1 定義了一個(gè)名為 press 的事件,它表示按下電燈開關(guān)的動(dòng)作。由于同一事件會(huì)打開和關(guān)閉一盞燈,因此只定義了一個(gè)事件。
定義所需的狀態(tài)和事件后,宏 BOOST_MSM_EUML_TRANSITION_TABLE 用于創(chuàng)建轉(zhuǎn)換表。該表定義了狀態(tài)之間的有效轉(zhuǎn)換以及哪些事件觸發(fā)了哪些狀態(tài)轉(zhuǎn)換。
BOOST_MSM_EUML_TRANSITION_TABLE 需要兩個(gè)參數(shù)。第一個(gè)參數(shù)定義了轉(zhuǎn)換表,第二個(gè)是轉(zhuǎn)換表的名稱。第一個(gè)參數(shù)的語法旨在使識(shí)別狀態(tài)和事件如何相互關(guān)聯(lián)變得容易。例如,Off + press == On 表示處于 Off 狀態(tài)的機(jī)器通過按下事件切換到 On 狀態(tài)。轉(zhuǎn)換表定義的直觀和不言自明的語法是 eUML 前端的優(yōu)勢(shì)之一。
創(chuàng)建轉(zhuǎn)換表后,使用宏 BOOST_MSM_EUML_DECLARE_STATE_MACHINE 定義狀態(tài)機(jī)。第二個(gè)參數(shù)也是更簡(jiǎn)單的一個(gè):它設(shè)置狀態(tài)機(jī)的名稱。示例 68.1 中的狀態(tài)機(jī)名為 light_state_machine。
BOOST_MSM_EUML_DECLARE_STATE_MACHINE 的第一個(gè)參數(shù)是一個(gè)元組。第一個(gè)值是轉(zhuǎn)換表的名稱。第二個(gè)值是一個(gè)使用 init_ 的表達(dá)式,它是 Boost.MetaStateMachine 提供的一個(gè)屬性。稍后您將了解有關(guān)屬性的更多信息。需要表達(dá)式 init_ << Off 將狀態(tài)機(jī)的初始狀態(tài)設(shè)置為 Off。
用 BOOST_MSM_EUML_DECLARE_STATE_MACHINE 定義的狀態(tài)機(jī) light_state_machine 是一個(gè)類。您使用此類從后端實(shí)例化狀態(tài)機(jī)。在示例 68.1 中,這是通過將 light_state_machine 作為參數(shù)傳遞給類模板 boost::msm::back::state_machine 來完成的。這會(huì)創(chuàng)建一個(gè)名為 light 的狀態(tài)機(jī)。
狀態(tài)機(jī)提供一個(gè)成員函數(shù) process_event() 來處理事件。如果您將事件傳遞給 process_event(),狀態(tài)機(jī)會(huì)根據(jù)其轉(zhuǎn)換表更改其狀態(tài)。
為了更容易看到多次調(diào)用 process_event() 時(shí)示例 68.1 中發(fā)生的情況,調(diào)用了 current_state()。此成員函數(shù)應(yīng)僅用于調(diào)試目的。它返回一個(gè)指向 int 的指針。每個(gè)狀態(tài)都是一個(gè) int 值,按照狀態(tài)在 BOOST_MSM_EUML_TRANSITION_TABLE 中被訪問的順序分配。在示例 68.1 中,Off 被賦予值 0,而 On 被賦予值 1。該示例將 0、1 和 0 寫入標(biāo)準(zhǔn)輸出。按下燈開關(guān)兩次,可以打開和關(guān)閉燈。
示例 68.2。具有狀態(tài)、事件和動(dòng)作的狀態(tài)機(jī)
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/state_grammar.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <iostream>
namespace msm = boost::msm;
using namespace boost::msm::front::euml;
BOOST_MSM_EUML_STATE((), Off)
BOOST_MSM_EUML_STATE((), On)
BOOST_MSM_EUML_EVENT(press)
BOOST_MSM_EUML_ACTION(switch_light)
{
template <class Event, class Fsm>
void operator()(const Event &ev, Fsm &fsm,
BOOST_MSM_EUML_STATE_NAME(Off) &sourceState,
BOOST_MSM_EUML_STATE_NAME(On) &targetState) const
{
std::cout << "Switching on\n";
}
template <class Event, class Fsm>
void operator()(const Event &ev, Fsm &fsm,
decltype(On) &sourceState,
decltype(Off) &targetState) const
{
std::cout << "Switching off\n";
}
};
BOOST_MSM_EUML_TRANSITION_TABLE((
Off + press / switch_light == On,
On + press / switch_light == Off
), light_transition_table)
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(
(light_transition_table, init_ << Off),
light_state_machine)
int main()
{
msm::back::state_machine<light_state_machine> light;
light.process_event(press);
light.process_event(press);
}示例 68.2 通過一個(gè)動(dòng)作擴(kuò)展了燈的狀態(tài)機(jī)。動(dòng)作由觸發(fā)狀態(tài)轉(zhuǎn)換的事件執(zhí)行。因?yàn)閯?dòng)作是可選的,所以可以在沒有它們的情況下定義狀態(tài)機(jī)。
操作是使用 BOOST_MSM_EUML_ACTION 定義的。嚴(yán)格來說,定義了一個(gè)函數(shù)對(duì)象。您必須重載運(yùn)算符 operator()。操作員必須接受四個(gè)參數(shù)。參數(shù)引用一個(gè)事件、一個(gè)狀態(tài)機(jī)和兩個(gè)狀態(tài)。您可以自由定義模板或?yàn)樗袇?shù)使用具體類型。在示例 68.2 中,僅為最后兩個(gè)參數(shù)設(shè)置具體類型。因?yàn)檫@些參數(shù)描述了開始和結(jié)束狀態(tài),所以您可以重載 operator() 以便為不同的開關(guān)執(zhí)行不同的成員函數(shù)。
請(qǐng)注意狀態(tài) On 和 Off 是對(duì)象。 Boost.MetaStateMachine 提供了一個(gè)宏 BOOST_MSM_EUML_STATE_NAME 來獲取狀態(tài)的類型。如果您使用 C++11,則可以使用運(yùn)算符 decltype 而不是宏。
switch_light 動(dòng)作已通過 BOOST_MSM_EUML_ACTION 定義,在按下燈開關(guān)時(shí)執(zhí)行。轉(zhuǎn)換表已相應(yīng)更改。第一個(gè)轉(zhuǎn)換現(xiàn)在是 Off + press / switch_light == On。您在事件后的斜線后傳遞操作。此轉(zhuǎn)換意味著如果當(dāng)前狀態(tài)為 Off 并且事件按下發(fā)生,則調(diào)用 switch_light 的運(yùn)算符 operator()。執(zhí)行操作后,新狀態(tài)為開啟。
示例 68.2 將 Switching on 然后 Switching off 寫入標(biāo)準(zhǔn)輸出。
示例 68.3。具有狀態(tài)、事件、守衛(wèi)和動(dòng)作的狀態(tài)機(jī)
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/state_grammar.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <iostream>
namespace msm = boost::msm;
using namespace boost::msm::front::euml;
BOOST_MSM_EUML_STATE((), Off)
BOOST_MSM_EUML_STATE((), On)
BOOST_MSM_EUML_EVENT(press)
BOOST_MSM_EUML_ACTION(is_broken)
{
template <class Event, class Fsm, class Source, class Target>
bool operator()(const Event &ev, Fsm &fsm, Source &src, Target &trg) const
{
return true;
}
};
BOOST_MSM_EUML_ACTION(switch_light)
{
template <class Event, class Fsm, class Source, class Target>
void operator()(const Event &ev, Fsm &fsm, Source &src, Target &trg) const
{
std::cout << "Switching\n";
}
};
BOOST_MSM_EUML_TRANSITION_TABLE((
Off + press [!is_broken] / switch_light == On,
On + press / switch_light == Off
), light_transition_table)
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(
(light_transition_table, init_ << Off),
light_state_machine)
int main()
{
msm::back::state_machine<light_state_machine> light;
light.process_event(press);
light.process_event(press);
}示例 68.3 在轉(zhuǎn)換表中使用了一個(gè)守衛(wèi)。第一個(gè)轉(zhuǎn)換的定義是 Off + press [!is_broken] / switch_light == On。在括號(hào)中傳遞 is_broken 意味著狀態(tài)機(jī)在調(diào)用動(dòng)作 switch_light 之前檢查是否可能發(fā)生轉(zhuǎn)換。這叫做守衛(wèi)。守衛(wèi)必須返回布爾類型的結(jié)果。
像 is_broken 這樣的守衛(wèi)是用 BOOST_MSM_EUML_ACTION 定義的,其方式與動(dòng)作相同。因此,必須為相同的四個(gè)參數(shù)重載運(yùn)算符 operator()。 operator() 必須有一個(gè) bool 類型的返回值才能用作守衛(wèi)。
請(qǐng)注意,您可以使用運(yùn)算符等邏輯運(yùn)算符!在括號(hào)內(nèi)的守衛(wèi)上。
如果運(yùn)行該示例,您會(huì)注意到?jīng)]有任何內(nèi)容寫入標(biāo)準(zhǔn)輸出。 switch_light 動(dòng)作未執(zhí)行 - 燈保持關(guān)閉狀態(tài)。守衛(wèi) is_broken 返回 true。但是,因?yàn)檫\(yùn)算符運(yùn)算符!使用時(shí),括號(hào)中的表達(dá)式的計(jì)算結(jié)果為 false。
您可以使用守衛(wèi)來檢查是否可以發(fā)生狀態(tài)轉(zhuǎn)換。示例 68.3 使用 is_broken 檢查燈是否壞了。雖然從關(guān)閉到打開的轉(zhuǎn)換通常是可能的,并且轉(zhuǎn)換表正確地描述了燈,但在此示例中,燈無法打開。盡管調(diào)用了兩次 process_event(),但燈的狀態(tài)為關(guān)閉。
示例 68.4。具有狀態(tài)、事件、進(jìn)入動(dòng)作和退出動(dòng)作的狀態(tài)機(jī)
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/state_grammar.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <iostream>
namespace msm = boost::msm;
using namespace boost::msm::front::euml;
BOOST_MSM_EUML_ACTION(state_entry)
{
template <class Event, class Fsm, class State>
void operator()(const Event &ev, Fsm &fsm, State &state) const
{
std::cout << "Entering\n";
}
};
BOOST_MSM_EUML_ACTION(state_exit)
{
template <class Event, class Fsm, class State>
void operator()(const Event &ev, Fsm &fsm, State &state) const
{
std::cout << "Exiting\n";
}
};
BOOST_MSM_EUML_STATE((state_entry, state_exit), Off)
BOOST_MSM_EUML_STATE((state_entry, state_exit), On)
BOOST_MSM_EUML_EVENT(press)
BOOST_MSM_EUML_TRANSITION_TABLE((
Off + press == On,
On + press == Off
), light_transition_table)
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(
(light_transition_table, init_ << Off),
light_state_machine)
int main()
{
msm::back::state_machine<light_state_machine> light;
light.process_event(press);
light.process_event(press);
}在示例 68.4 中,傳遞給 BOOST_MSM_EUML_STATE 的第一個(gè)參數(shù)是一個(gè)由 state_entry 和 state_exit 組成的元組。 state_entry 是進(jìn)入動(dòng)作,state_exit 是退出動(dòng)作。這些動(dòng)作在進(jìn)入或退出狀態(tài)時(shí)執(zhí)行。
與操作一樣,進(jìn)入和退出操作是使用 BOOST_MSM_EUML_ACTION 定義的。但是,重載運(yùn)算符 operator() 只需要三個(gè)參數(shù):對(duì)事件的引用、狀態(tài)機(jī)和狀態(tài)。狀態(tài)之間的轉(zhuǎn)換對(duì)于進(jìn)入和退出操作無關(guān)緊要,因此只需將一個(gè)狀態(tài)傳遞給 operator()。對(duì)于進(jìn)入動(dòng)作,進(jìn)入該狀態(tài)。對(duì)于退出操作,此狀態(tài)已退出。
在示例 68.4 中,狀態(tài) Off 和 On 都有進(jìn)入和退出操作。因?yàn)槭录聪掳l(fā)生了兩次,所以 Entering 和 Exiting 顯示了兩次。請(qǐng)注意,Exiting 會(huì)先顯示,Entering 會(huì)顯示在后面,因?yàn)閳?zhí)行的第一個(gè)操作是退出操作。
第一個(gè)事件按下觸發(fā)從關(guān)閉到開啟的轉(zhuǎn)換,退出和進(jìn)入各顯示一次。第二次事件按下將狀態(tài)切換為關(guān)閉。 Exiting 和 Entering 再次顯示一次。因此,狀態(tài)轉(zhuǎn)換首先執(zhí)行退出動(dòng)作,然后執(zhí)行新狀態(tài)的進(jìn)入動(dòng)作。
示例 68.5。狀態(tài)機(jī)中的屬性
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/state_grammar.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <iostream>
namespace msm = boost::msm;
using namespace boost::msm::front::euml;
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int, switched_on)
BOOST_MSM_EUML_ACTION(state_entry)
{
template <class Event, class Fsm, class State>
void operator()(const Event &ev, Fsm &fsm, State &state) const
{
std::cout << "Switched on\n";
++fsm.get_attribute(switched_on);
}
};
BOOST_MSM_EUML_ACTION(is_broken)
{
template <class Event, class Fsm, class Source, class Target>
bool operator()(const Event &ev, Fsm &fsm, Source &src, Target &trg) const
{
return fsm.get_attribute(switched_on) > 1;
}
};
BOOST_MSM_EUML_STATE((), Off)
BOOST_MSM_EUML_STATE((state_entry), On)
BOOST_MSM_EUML_EVENT(press)
BOOST_MSM_EUML_TRANSITION_TABLE((
Off + press [!is_broken] == On,
On + press == Off
), light_transition_table)
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(
(light_transition_table, init_ << Off, no_action, no_action,
attributes_ << switched_on), light_state_machine)
int main()
{
msm::back::state_machine<light_state_machine> light;
light.process_event(press);
light.process_event(press);
light.process_event(press);
light.process_event(press);
light.process_event(press);
}示例 68.5 使用守衛(wèi) is_broken 檢查是否可以從 Off 到 On 的狀態(tài)轉(zhuǎn)換。這次 is_broken 的返回值取決于電燈開關(guān)被按下的頻率??梢栽跓魤闹皩舸蜷_兩次。為了計(jì)算燈打開的頻率,使用了一個(gè)屬性。
屬性是可以附加到對(duì)象的變量。它們?cè)试S您在運(yùn)行時(shí)調(diào)整狀態(tài)機(jī)的行為。因?yàn)橹T如開燈頻率之類的數(shù)據(jù)必須存儲(chǔ)在某個(gè)地方,所以將其直接存儲(chǔ)在狀態(tài)機(jī)、狀態(tài)或事件中是有意義的。
在使用屬性之前,必須對(duì)其進(jìn)行定義。這是通過宏 BOOST_MSM_EUML_DECLARE_ATTRIBUTE 完成的。傳遞給 BOOST_MSM_EUML_DECLARE_ATTRIBUTE 的第一個(gè)參數(shù)是類型,第二個(gè)是屬性的名稱。示例 68.5 定義了 int 類型的屬性 switched_on。
定義屬性后,必須將其附加到對(duì)象。該示例將屬性 switched_on 附加到狀態(tài)機(jī)。這是通過元組中的第五個(gè)值完成的,該值作為第一個(gè)參數(shù)傳遞給 BOOST_MSM_EUML_DECLARE_STATE_MACHINE。使用 attributes_,來自 Boost.MetaStateMachine 的關(guān)鍵字用于創(chuàng)建 lambda 函數(shù)。要將屬性 switched_on 附加到狀態(tài)機(jī),請(qǐng)使用 operator<< 將 switched_on 寫入 attributes_,就好像它是一個(gè)流一樣。
元組中的第三個(gè)和第四個(gè)值都設(shè)置為 no_action。該屬性作為元組中的第五個(gè)值傳遞。第三個(gè)和第四個(gè)值可用于定義狀態(tài)機(jī)的進(jìn)入和退出操作。如果沒有定義進(jìn)入和退出操作,請(qǐng)使用 no_action。
將屬性附加到狀態(tài)機(jī)后,可以使用 get_attribute() 訪問它。在示例 68.5 中,此成員函數(shù)在入口操作 state_entry 中被調(diào)用以增加屬性的值。因?yàn)?state_entry 僅鏈接到狀態(tài) On,switched_on 僅在燈打開時(shí)遞增。
switched_on 也可以從守衛(wèi) is_broken 訪問,它檢查屬性的值是否大于 1。如果是,守衛(wèi)返回 true。由于屬性是使用默認(rèn)構(gòu)造函數(shù)初始化的,并且 switched_on 設(shè)置為 0,如果燈已打開兩次,is_broken 將返回 true。
在示例 68.5 中,事件按下發(fā)生了五次。燈被打開和關(guān)閉兩次,然后再次打開。燈打開的前兩次會(huì)顯示“已打開”。但是,第三次打開燈時(shí)沒有輸出。發(fā)生這種情況是因?yàn)?is_broken 在燈被打開兩次后返回 true,因此,沒有從 Off 到 On 的狀態(tài)轉(zhuǎn)換。這意味著不執(zhí)行狀態(tài) On 的進(jìn)入操作,并且該示例不寫入標(biāo)準(zhǔn)輸出。
示例 68.6。訪問轉(zhuǎn)換表中的屬性
#include <boost/msm/front/euml/euml.hpp>
#include <boost/msm/front/euml/state_grammar.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <iostream>
namespace msm = boost::msm;
using namespace boost::msm::front::euml;
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int, switched_on)
void write_message()
{
std::cout << "Switched on\n";
}
BOOST_MSM_EUML_FUNCTION(WriteMessage_, write_message, write_message_,
void, void)
BOOST_MSM_EUML_STATE((), Off)
BOOST_MSM_EUML_STATE((), On)
BOOST_MSM_EUML_EVENT(press)
BOOST_MSM_EUML_TRANSITION_TABLE((
Off + press [fsm_(switched_on) < Int_<2>()] / (++fsm_(switched_on),
write_message_()) == On,
On + press == Off
), light_transition_table)
BOOST_MSM_EUML_DECLARE_STATE_MACHINE(
(light_transition_table, init_ << Off, no_action, no_action,
attributes_ << switched_on), light_state_machine)
int main()
{
msm::back::state_machine<light_state_machine> light;
light.process_event(press);
light.process_event(press);
light.process_event(press);
light.process_event(press);
light.process_event(press);
}示例 68.6 與示例 68.5 做同樣的事情:將燈打開兩次后,燈壞了,無法再打開。雖然前面的示例在操作中訪問了 switched_on 屬性,但此示例使用轉(zhuǎn)換表中的屬性。
Boost.MetaStateMachine 提供函數(shù) fsm_() 來訪問狀態(tài)機(jī)中的屬性。這樣就定義了一個(gè)守衛(wèi)來檢查 switched_on 是否小于 2。并且定義了一個(gè)動(dòng)作,每次狀態(tài)從 Off 切換到 On 時(shí)都會(huì)增加 switched_on。
請(qǐng)注意,守衛(wèi)中的小于比較是通過 Int_<2>() 完成的。數(shù)字 2 必須作為模板參數(shù)傳遞給 Int_ 以創(chuàng)建此類的實(shí)例。這將創(chuàng)建一個(gè)具有 Boost.MetaStateMachine 所需類型的函數(shù)對(duì)象。
示例 68.6 還使用宏 BOOST_MSM_EUML_FUNCTION 使函數(shù)成為動(dòng)作。傳遞給 BOOST_MSM_EUML_FUNCTION 的第一個(gè)參數(shù)是可以在函數(shù)前端使用的動(dòng)作的名稱。第二個(gè)參數(shù)是函數(shù)的名稱。第三個(gè)參數(shù)是在 eUML 中使用的操作名稱。第四個(gè)和第五個(gè)參數(shù)是函數(shù)的返回值——一個(gè)用于動(dòng)作用于狀態(tài)轉(zhuǎn)換的情況,另一個(gè)用于動(dòng)作描述進(jìn)入或退出動(dòng)作的情況。以這種方式將 write_message() 轉(zhuǎn)換為動(dòng)作后,將在轉(zhuǎn)換表中的 ++fsm_(switched_on) 之后創(chuàng)建并使用 write_message_ 類型的對(duì)象。在從 Off 到 On 的狀態(tài)轉(zhuǎn)換中,屬性 switched_on 遞增,然后調(diào)用 write_message()。
與示例 68.5 中一樣,示例 68.6 顯示兩次打開。
Boost.MetaStateMachine 提供額外的函數(shù),例如 state_() 和 event_(),以訪問附加到其他對(duì)象的屬性。其他類,例如 Char_ 和 String_,也可以像 Int_ 一樣使用。
提示
正如您在示例中看到的,前端 eUML 要求您使用許多宏。頭文件 boost/msm/front/euml/common.hpp 包含所有 eUML 宏的定義,這使其成為一個(gè)有用的參考。
練習(xí)
為可以關(guān)閉、打開或傾斜的窗口創(chuàng)建狀態(tài)機(jī)。關(guān)閉的窗戶可以打開或傾斜。如果不先關(guān)閉打開的窗戶,則無法傾斜它。傾斜的窗戶也不能在不先關(guān)閉的情況下打開。通過打開和傾斜您的窗口幾次來測(cè)試您的狀態(tài)機(jī)。使用 current_state() 將狀態(tài)寫入標(biāo)準(zhǔn)輸出。
擴(kuò)展?fàn)顟B(tài)機(jī):窗戶應(yīng)該是智能家居的一部分。狀態(tài)機(jī)現(xiàn)在應(yīng)該計(jì)算窗戶打開和傾斜的頻率。要測(cè)試您的狀態(tài)機(jī),請(qǐng)打開并傾斜您的窗口幾次。在程序結(jié)束時(shí),將窗口打開的頻率和傾斜的頻率寫入標(biāo)準(zhǔn)輸出。
到此這篇關(guān)于C++ Boost MetaStateMachine定義狀態(tài)機(jī)超詳細(xì)講解的文章就介紹到這了,更多相關(guān)C++ Boost MetaStateMachine內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++11 std::shared_ptr總結(jié)與使用示例代碼詳解
這篇文章主要介紹了C++11 std::shared_ptr總結(jié)與使用,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
VS2019調(diào)試C語言程序(監(jiān)視操作)的詳細(xì)步驟
在很多時(shí)候我們?cè)趯懗绦虻倪^程中會(huì)發(fā)現(xiàn)一些非編程錯(cuò)誤的問題,這樣的問題很難直接分辨出來,但是我們可以用調(diào)試了一步一步的模擬程序運(yùn)行的過程,來找出程序的錯(cuò)誤,下面這篇文章主要給大家介紹了關(guān)于VS2019調(diào)試C語言程序(監(jiān)視操作)的詳細(xì)步驟,需要的朋友可以參考下2022-11-11
C++實(shí)現(xiàn)圖書信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)圖書信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
ubuntu20.04中vscode使用ROS的詳細(xì)方法
這篇文章主要介紹了ubuntu20.04?vscode使用ROS的詳細(xì)方法,主要包括在vscode安裝擴(kuò)展創(chuàng)建工作文件夾的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10
C語言數(shù)學(xué)問題與簡(jiǎn)單DP01背包問題詳解
這篇文章主要介紹了C語言數(shù)學(xué)問題買不到的數(shù)目、螞蟻感冒、飲料換購與簡(jiǎn)單DP01背包問題的解決,屬于藍(lán)橋杯省賽中的題目,感興趣的同學(xué)來看看吧2022-04-04

