Home > OS >  Forward declare a templated typedef
Forward declare a templated typedef

Time:12-06

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_
>;

Demo

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.

  • Related