In my public header, I am trying to add a pointer to an object which is only defined privately. Normally that would be simple. I just forward-declare. However, the object is a bit complicated and I'm not sure how to forward declare it.
public.h:
#include <memory>
class StateMachine; // This forward declaration doesn't work
class MyClass {
std::unique_ptr<StateMachine> sm_;
public:
MyClass();
}
public.cpp
#include <public.h>
#include "statemachine.h" //StateMachine declared in full here
MyClass::MyClass
: obj_(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;
where boost::msm::back::state_machine
is defined as:
template <
class A0
, class A1 = parameter::void_
, class A2 = parameter::void_
, class A3 = parameter::void_
, class A4 = parameter::void_
>
class state_machine { ... };
Here are some of the forward-declarations I've tried and their error messages (g )
class StateMachine;
error: conflicting declaration ‘typedef class boost::msm::back::state_machine<_StateMachine> StateMachine’
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
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)
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: error: wrong number of template arguments (1, should be 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’
CodePudding user response:
If you really don't want to include boost/msm/back/state_machine.hpp
, then you need to forward-declare state_machine
and use it correctly.
Your attempt fails because T1
, T2
, T3
, and T4
are not given a type when instantiated.
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
/* need types here, we don't know there are default ones defined later */
> StateMachine;
Your attempt with class Void;
fails because Void
is not parameter::void_
, so the two typedefs are different.
Note before the solution: in C , you should probably use using
instead of typedef
. Also, in C 17, you can do namespace boost::msm::back { ... }
.
The solution is to forward declare parameter::void_
as well and use it in the alias definition.
namespace boost::msm::back {
namespace parameter {
// careful, this might be in a different namespace if there is a using namespace somewhere.
class void_;
}
template<class T0, class T1, class T2, class T3, class T4> class state_machine;
}
class _StateMachine;
using StateMachine = boost::msm::back::state_machine<
_StateMachine,
boost::msm::back::parameter::void_,
boost::msm::back::parameter::void_,
boost::msm::back::parameter::void_,
boost::msm::back::parameter::void_
>;
Unfortunately, you cannot provide T1
through T4
with default types because you cannot have multiple declarations of the default parts of template parameter lists, even if they match.
I don't see any other solution than this or including the boost header.