如何前置声明由模板化typedef定义的StateMachine类?
在公共头文件中需要声明一个指向私有定义对象的指针,通常用前置声明即可,但此处的StateMachine是由Boost MSM模板typedef生成的,普通前置声明无效,需要找到正确的前置声明方式。
现有代码结构
public.h
#include <memory> class StateMachine; // 该前置声明无效 class MyClass { std::unique_ptr<StateMachine> sm_; public: MyClass(); };
public.cpp
#include <public.h> #include "statemachine.h" // 此处完整声明StateMachine MyClass::MyClass : sm_(std::make_unique<StateMachine>(*this)) { }
statemachine.h
#include <boost/msm/back/state_machine.hpp> #include <boost/msm/front/state_machine.hpp> class MyClass; struct _StateMachine : public boost::msm::front::state_machine_def<_StateMachine> { MyClass parent_; public: _StateMachine(MyClass& p_parent); }; typedef boost::msm::back::state_machine<_StateMachine> StateMachine;
Boost MSM中state_machine的模板定义
template < class A0 , class A1 = parameter::void_ , class A2 = parameter::void_ , class A3 = parameter::void_ , class A4 = parameter::void_ > class state_machine { ... };
尝试过的前置声明及报错
尝试1:
class StateMachine;报错:
error: conflicting declaration ‘typedef class boost::msm::back::state_machine<_StateMachine> StateMachine’尝试2:
namespace boost{ namespace msm { namespace back { class state_machine; }}} typedef boost::msm::back::state_machine StateMachine;报错:
error: ‘boost::msm::back::state_machine’ is not a template尝试3:
namespace boost{ namespace msm { namespace back { template <class T> class state_machine; }}} class _StateMachine; typedef boost::msm::state_machine<_StateMachine> StateMachine;报错:
error: wrong number of template arguments (5, should be 1)尝试4:
namespace boost{ namespace msm { namespace back { template<class T0, class T1, class T2, class T3, class T4> class state_machine; }}} class _StateMachine; typedef boost::msm::back::state_machine<_StateMachine> StateMachine;报错:
error: wrong number of template arguments (1, should be 5)尝试5:
namespace boost{ namespace msm { namespace back { template<class T0, class T1, class T2, class T3, class T4> class state_machine; }}} class _StateMachine; class Void; typedef boost::msm::back::state_machine<_StateMachine, Void, Void, Void, Void> StateMachine;报错:
error: conflicting declaration ‘typedef class boost::msm::back::state_machine<_StateMachine> StateMachine’
正确解决方法
方法1:完整前置声明模板与依赖结构
在public.h中,需要匹配statemachine.h中的typedef逻辑,正确前置声明模板和内部结构体:
#include <memory> // 前置声明Boost MSM的back::state_machine模板 namespace boost { namespace msm { namespace back { template <class A0, class A1 = void, class A2 = void, class A3 = void, class A4 = void> class state_machine; } // namespace back } // namespace msm } // namespace boost // 前置声明_StateMachine结构体 struct _StateMachine; // 与statemachine.h一致的typedef typedef boost::msm::back::state_machine<_StateMachine> StateMachine; class MyClass { std::unique_ptr<StateMachine> sm_; public: MyClass(); };
注:用void替代parameter::void_作为占位符即可,编译器在看到完整定义时会自动匹配。
方法2:使用Pimpl惯用法隐藏实现(更简洁)
如果不想处理复杂的模板前置声明,推荐用Pimpl封装实现细节:
修改public.h:
#include <memory> class MyClassImpl; class MyClass { std::unique_ptr<MyClassImpl> impl_; public: MyClass(); ~MyClass(); // 需在cpp中定义,因unique_ptr需要完整类型 };
创建私有头文件myclass_impl.h:
#include "public.h" #include "statemachine.h" class MyClassImpl { public: std::unique_ptr<StateMachine> sm_; MyClassImpl(MyClass& parent) : sm_(std::make_unique<StateMachine>(parent)) {} };
修改public.cpp:
#include <public.h> #include "myclass_impl.h" MyClass::MyClass() : impl_(std::make_unique<MyClassImpl>(*this)) {} MyClass::~MyClass() = default;
这种方式完全不需要在公共头文件中处理StateMachine的前置声明,实现了更好的封装。
内容的提问来源于stack exchange,提问作者Stewart

