I’m an old C-dude that tries to learn about C++11 by porting my old state-machine framework from C to C++11. My idea is to have a class for the state-machine itself and then nested classes for the states within. The states may be hierarchical, i.e. super- and substates. The framework needs to know about a state’s superstate and for that I have a pointer (state *superstate) in the nested state class.
My problem is that I intended to set the superstate-pointer by using the constructor directly within the machine’s class, which should be possible in C++11 with non-static data member initialization, by using uniform initialization. But some reason it fails to compile (substateB3{superstateA}) when set to another type of state/class. But it works fine if I later set it by using a specific function (set_superstate) for this purpose, which has the same argument as the constructor! And funny enough the constructor is accepted if I set the superstate to a state/class of same type (substateB2{substateB1}).
I’m using gcc 4.7.0 (to get support for non-static data member initializers) and here’s my code:
// My state-machine framework (simplified)
struct machine {
struct state {
state() : superstate(nullptr) { } // No superstate => toplevel state!
state(state &superstate) : superstate(&superstate) { }
state *superstate;
void set_superstate(state &superstate) { this->superstate = &superstate; } // Non-ctor way to set superstate
};
};
// An example of a specific state-machine using my framework
struct Machine : machine {
struct SuperstateA : state {
} superstateA;
struct SubstateB : state {
} substateB1, // Compiles OK; gets its superstate set in Machine's ctor below
substateB2{substateB1}, // Compiles OK; but not correct superstate
substateB3{superstateA}; // gcc 4.7.0 error: could not convert ‘{((Machine*)this)->Machine::superstateA}’ from ‘<brace-enclosed initializer list>’ to ‘Machine::SubstateB’
Machine() { substateB1.set_superstate(superstateA); } // Compiles OK;
} myMachine;
Any tips or guidance are much appreciated thanks! 🙂
Stripping one layer of inheritance:
You’re getting the construction error because your substates declare no constructors so they’re getting the compiler-provided defaults, and there is none from a sibling- or base- class reference (the compiler doesn’t provide
s2(s1&)ors2(state&)).You’re getting the wrong superstate for
CbecauseC{B}invokes the default copy constructors2(s2&), which runs beforem()‘s body.Here’s what you want instead:
When M’s constructor runs, first its base classes (there are none) then its members are constructed in declaration order using the specified initializations. There’s only one:
B(A), so all the rest are defaulted. After all the bases and members are constructed, then the object constructor’s body runs.