Reputation: 7344
First, I manage to implement a state machine in a single header file. I know I need some forward declarations, and I have to define the states from outside to inside. What I really don't understand is: How would I do this with multiple files?
My aproach:
Then it looks like this:
// forward.h
struct Machine;
struct StA;
struct StB;
// machine.h
#include "forward.h"
struct Machine : sc::state_machine< Machine, StA > {};
// a.h
#include "forward.h" // for StB
#include "machine.h"
struct StA : sc::simple_state< StA, Machine, StB > {};
// b.h
#include "forward.h"
#include "a.h"
struct StB : sc::simple_state< StB, StA > {};
Now it's left open how to include the whole thing in the program. My idea was to have one header which includes from outside to inside all the states' headers.
// the_machine.h
#include "forward.h"
#include "machine.h"
#include "a.h"
#include "b.h"
// use this header now where you need the state machine
However, I don't know if the general idea is ok and even if so, I can't get this to compile (well, not exactly this but a machine I built following this design principle). Having all in one file it pretty easy once you reaized that context needs to be complete, states need to be forward declared and so on, but splitting for complexity and maintenance reasons frays my nerves ... Incomplete type 'StXY' used in nested name specifier
and so on.
Upvotes: 1
Views: 685
Reputation: 24626
The Incomplete type
error often appears if you have messed up the order in which headers get included.
Try the follwing: create an empty .cpp that just includes the_machine.h
and only precompile it. There are command line flags for the different compilers that write a file containing the preprocessed translation unit (i.e. one file con0taining all the code the compiler gets to see). Check that file to see if everything is in the order you think it is. Most preprocessors generate #line
control commands, telling the compiler (and you) what line of what header/source you are looking at.
Edit:
If you want to just #include
machine.h, you will have to include the state definitions after the machine definition. That might look odd at a first glance, but this is how it works with templates in general, if you want to split dependant parts. Many people use different file suffixes for the later included parts, because those are no real headers on their own, i.e. you can't include them solely. Example:
//Something.h
template <class T>
struct Something
{
void meow(T const& t);
int wuff(T const& t, int b);
};
#include "Something.impl" //or .ipp, or other endings...
//Something.impl
template <class T>
void Something<T>::meow(T const& t)
{ /* implement... */ }
template <class T>
int Something<T>::wuff(T const& t, int b)
{ /* implement... */ }
Your machine.h would look similar - define the machine and include implementations of the states after it. I would not name states' implementation files X.h
, because they are no single headers one could just include and use on their own.
Upvotes: 2