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 的簡單狀態(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 使用了最簡單的狀態(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)勢之一。
創(chuàng)建轉(zhuǎn)換表后,使用宏 BOOST_MSM_EUML_DECLARE_STATE_MACHINE 定義狀態(tài)機(jī)。第二個(gè)參數(shù)也是更簡單的一個(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ù)。
請注意狀態(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)。
請注意,您可以使用運(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 顯示了兩次。請注意,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ì)象的變量。它們允許您在運(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ī),請使用 operator<< 將 switched_on 寫入 attributes_,就好像它是一個(gè)流一樣。
元組中的第三個(gè)和第四個(gè)值都設(shè)置為 no_action。該屬性作為元組中的第五個(gè)值傳遞。第三個(gè)和第四個(gè)值可用于定義狀態(tài)機(jī)的進(jìn)入和退出操作。如果沒有定義進(jìn)入和退出操作,請使用 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。
請注意,守衛(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)閉的情況下打開。通過打開和傾斜您的窗口幾次來測試您的狀態(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ì)算窗戶打開和傾斜的頻率。要測試您的狀態(tài)機(jī),請打開并傾斜您的窗口幾次。在程序結(jié)束時(shí),將窗口打開的頻率和傾斜的頻率寫入標(biāo)準(zhǔn)輸出。
到此這篇關(guān)于C++ Boost MetaStateMachine定義狀態(tài)機(jī)超詳細(xì)講解的文章就介紹到這了,更多相關(guān)C++ Boost MetaStateMachine內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
OpenCV4.1.0+VisualStudio2019開發(fā)環(huán)境搭建(超級(jí)簡單)
這篇文章主要介紹了OpenCV4.1.0+VisualStudio2019開發(fā)環(huán)境搭建(超級(jí)簡單),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03C語言數(shù)據(jù)結(jié)構(gòu)之線索二叉樹及其遍歷
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)之線索二叉樹及其遍歷的相關(guān)資料,為了加快查找節(jié)點(diǎn)的前驅(qū)和后繼。對(duì)二叉樹的線索化就是對(duì)二叉樹進(jìn)行一次遍歷,在遍歷的過程中檢測節(jié)點(diǎn)的左右指針是否為空,如果是空,則將他們改為指向前驅(qū)和后繼節(jié)點(diǎn)的線索,需要的朋友可以參考下2017-08-08C++的std::transform()的實(shí)現(xiàn)
在 C++ 標(biāo)準(zhǔn)庫中,std::transform() 是一個(gè)非常有用的算法函數(shù),它能夠?qū)⒔o定范圍中的每個(gè)元素進(jìn)行變換,并將變換后的結(jié)果存儲(chǔ)到另一個(gè)范圍中,本文就詳細(xì)的介紹一下具體用法,感興趣的可以了解一下2023-08-08c++ 獲取數(shù)字字符串的子串?dāng)?shù)值性能示例分析
這篇文章主要為大家介紹了c++ 獲取數(shù)字字符串的子串?dāng)?shù)值示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11利用Qt+opencv實(shí)現(xiàn)視頻分解為圖片
這篇文章主要為大家詳細(xì)介紹了如何利用Qt和opencv實(shí)現(xiàn)視頻分解為圖片,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12如何基于 Blueprint 在游戲中創(chuàng)建實(shí)時(shí)音視頻功能
我們在本文先來講講如何在 Unreal 中用 Blueprint 快速實(shí)現(xiàn)。稍后會(huì)分享基于 C++的實(shí)現(xiàn)步驟。感興趣的朋友跟隨小編一起看看吧2020-05-05C/C++?Qt?TableDelegate?自定義代理組件使用詳解
TableDelegate自定義代理組件的主要作用是對(duì)原有表格進(jìn)行調(diào)整,本文主要介紹了QT中TableDelegate?自定義代理組件的使用教程,感興趣的朋友可以了解一下2021-12-12