Finding a max for an enum - a template problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Kevin

    Finding a max for an enum - a template problem

    I'm creating a template to support state machines. In doing so, I
    need to pass an enumeration for the number of transitions and a non
    type parameter for the range of the enum (to allow me to allocate an
    array of pointers big enough to hold one entry for each transition).
    My template declaration looks roughly like this:

    template <class TRANSITION, int NUMTRANSITIONS>
    class StateMachine {
    ***SNIP***
    void RegisterTransit ion(TRANSITION t, StateMachine *pState);
    StateMachine *nextState[NUMTRANSITIONS];
    ***SNIP***
    };


    I invoke the template like so:

    // Define an enumerated type for transitions
    enum ToggleSwitch_t { ON, OFF, TOGGLE };
    #define MAX_TRANSITION 3

    // Set up a pointer to current state
    StateMachine<To ggleSwitch_t, MAX_TRANSITION* pCurrState;

    // Create states
    StateMachine<To ggleSwitch_t, MAX_TRANSITION> LightOn("LIGHT ON");
    StateMachine<To ggleSwitch_t, MAX_TRANSITIONL ightOff("LIGHT OFF");

    // Set up transitions
    LightOn.Registe rTransition(ON, &LightOn);
    LightOn.Registe rTransition(OFF , &LightOff);
    LightOn.Registe rTransition(TOG GLE, &LightOff);

    LightOff.Regist erTransition(ON , &LightOn);
    LightOff.Regist erTransition(OF F, &LightOff);
    LightOff.Regist erTransition(TO GGLE, &LightOn);

    It works fine as is, but I want to add a static array that will allow
    me to index into states as an enum type. I could set up something
    like

    template <class TRANSITION, int NUMTRANSITIONS, class STATE, int
    NUMSTATES>

    but this is going to get very hairy very quickly. I would prefer if I
    could somehow take the enum that's passed in and simply derive its
    maximum from inside the template itself. That would give me something
    easier to read like

    template <class TRANSITION, class STATE>

    I can't find any way to determine the max value of an enum. Most
    previous posts are of the form "You can't do that - please try
    workaround XYZ..." If I must, I could try using #define macros, but
    that just seems to hide the mechanics rather than simplifying them,
    which is a sure recipe for confusion for maintenance programming.

    Does anyone have any suggestions?

    Thanks,

    Kevin

  • Victor Bazarov

    #2
    Re: Finding a max for an enum - a template problem

    Kevin wrote:
    [..] I would prefer if I
    could somehow take the enum that's passed in and simply derive its
    maximum from inside the template itself.
    There is no way.
    [..]
    I can't find any way to determine the max value of an enum.
    Because there is none.
    Most
    previous posts are of the form "You can't do that - please try
    workaround XYZ..." If I must, I could try using #define macros, but
    that just seems to hide the mechanics rather than simplifying them,
    which is a sure recipe for confusion for maintenance programming.
    >
    Does anyone have any suggestions?
    You can't do that - please try workaround: each "enum" should not
    really be an enum, but an array of, say, unsigned, wrapped in a class
    or a struct (to make it a different type). The array of values will
    have its size, from which you can determine when you hit the end of
    the array, thus going through all values.

    Enums are ancient and not very suitable for state machine modelling.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask


    Comment

    • liverspot@gmail.com

      #3
      Re: Finding a max for an enum - a template problem

      You can do something like

      enum ToggleSwitch_t { ON, OFF, TOGGLE, LAST };

      and then take the value of LAST. You would need LAST to be the last
      element in every enum you want to use.


      On Jun 21, 12:57 pm, Kevin <k...@collins.r ockwell.comwrot e:
      I'm creating a template to support state machines. In doing so, I
      need to pass an enumeration for the number of transitions and a non
      type parameter for the range of the enum (to allow me to allocate an
      array of pointers big enough to hold one entry for each transition).
      My template declaration looks roughly like this:
      >
      template <class TRANSITION, int NUMTRANSITIONS>
      class StateMachine {
      ***SNIP***
      void RegisterTransit ion(TRANSITION t, StateMachine *pState);
      StateMachine *nextState[NUMTRANSITIONS];
      ***SNIP***
      };
      >
      I invoke the template like so:
      >
      // Define an enumerated type for transitions
      enum ToggleSwitch_t { ON, OFF, TOGGLE };
      #define MAX_TRANSITION 3
      >
      // Set up a pointer to current state
      StateMachine<To ggleSwitch_t, MAX_TRANSITION* pCurrState;
      >
      // Create states
      StateMachine<To ggleSwitch_t, MAX_TRANSITION> LightOn("LIGHT ON");
      StateMachine<To ggleSwitch_t, MAX_TRANSITIONL ightOff("LIGHT OFF");
      >
      // Set up transitions
      LightOn.Registe rTransition(ON, &LightOn);
      LightOn.Registe rTransition(OFF , &LightOff);
      LightOn.Registe rTransition(TOG GLE, &LightOff);
      >
      LightOff.Regist erTransition(ON , &LightOn);
      LightOff.Regist erTransition(OF F, &LightOff);
      LightOff.Regist erTransition(TO GGLE, &LightOn);
      >
      It works fine as is, but I want to add a static array that will allow
      me to index into states as an enum type. I could set up something
      like
      >
      template <class TRANSITION, int NUMTRANSITIONS, class STATE, int
      NUMSTATES>
      >
      but this is going to get very hairy very quickly. I would prefer if I
      could somehow take the enum that's passed in and simply derive its
      maximum from inside the template itself. That would give me something
      easier to read like
      >
      template <class TRANSITION, class STATE>
      >
      I can't find any way to determine the max value of an enum. Most
      previous posts are of the form "You can't do that - please try
      workaround XYZ..." If I must, I could try using #define macros, but
      that just seems to hide the mechanics rather than simplifying them,
      which is a sure recipe for confusion for maintenance programming.
      >
      Does anyone have any suggestions?
      >
      Thanks,
      >
      Kevin

      Comment

      • Kevin

        #4
        Re: Finding a max for an enum - a template problem

        On Jun 21, 10:06 am, "Victor Bazarov" <v.Abaza...@com Acast.netwrote:

        You can't do that - please try workaround: each "enum" should not
        really be an enum, but an array of, say, unsigned, wrapped in a class
        or a struct (to make it a different type). The array of values will
        have its size, from which you can determine when you hit the end of
        the array, thus going through all values.
        >
        >
        So, something like:
        template <int TRANSITIONS[], int STATES[]>
        class StateMachine {
        ***SNIP***
        StateMachine *nextState[sizeof(TRANSITI ONS)];
        ***SNIP***
        };

        And

        #define ON 1
        #define OFF 2
        #define TOGGLE 3
        int MyTrans[] = {ON, OFF, TOGGLE};

        #define LIGHT_ON 1
        #define LIGHT_OFF 2
        int MyStates[] = {LIGHT_ON, LIGHT_OFF, TOGGLE};

        StateMachine<My Trans, MyStates>LightO n("LIGHT IS ON");
        StateMachine<My Trans, MyStatesLightOf f("LIGHT IS OFF");

        Does that seem right?

        - Kevin

        Comment

        • Victor Bazarov

          #5
          Re: Finding a max for an enum - a template problem

          Kevin wrote:
          On Jun 21, 10:06 am, "Victor Bazarov" <v.Abaza...@com Acast.netwrote:
          >
          >
          >You can't do that - please try workaround: each "enum" should not
          >really be an enum, but an array of, say, unsigned, wrapped in a class
          >or a struct (to make it a different type). The array of values will
          >have its size, from which you can determine when you hit the end of
          >the array, thus going through all values.
          >>
          >>
          >
          So, something like:
          template <int TRANSITIONS[], int STATES[]>
          class StateMachine {
          ***SNIP***
          StateMachine *nextState[sizeof(TRANSITI ONS)];
          Probably

          StateMachine *nextState[sizeof(TRANSITI ONS) / sizeof(int)];

          (sizeof does not report the *number* of elements, but their combined
          size in bytes).
          ***SNIP***
          };
          >
          And
          >
          #define ON 1
          #define OFF 2
          #define TOGGLE 3
          int MyTrans[] = {ON, OFF, TOGGLE};
          >
          #define LIGHT_ON 1
          #define LIGHT_OFF 2
          int MyStates[] = {LIGHT_ON, LIGHT_OFF, TOGGLE};
          >
          StateMachine<My Trans, MyStates>LightO n("LIGHT IS ON");
          StateMachine<My Trans, MyStatesLightOf f("LIGHT IS OFF");
          >
          Does that seem right?
          Since you're asking in response to my reply, I feel I need to give you
          an answer, but you're not going to like it, I'm afraid... Here it is:
          I have no idea. If it solves the problem you had, then use it. If it
          does not, let's talk more, perhaps you'll get me to understand what it
          is you hope to accomplish.

          I know that enums are not well suited for your task, they are very low
          level and very limited functionality types. That's why I suggested
          dumping them altogether. You are better off creating a separate type
          for every state set/sequence you need to identify. Each state then
          could be expressed/encoded by a value.

          V
          --
          Please remove capital 'A's when replying by e-mail
          I do not respond to top-posted replies, please don't ask


          Comment

          • James Kanze

            #6
            Re: Finding a max for an enum - a template problem

            On Jun 21, 8:54 pm, "Victor Bazarov" <v.Abaza...@com Acast.netwrote:
            Kevin wrote:
            On Jun 21, 10:06 am, "Victor Bazarov" <v.Abaza...@com Acast.netwrote:
            [...]
            Since you're asking in response to my reply, I feel I need to give you
            an answer, but you're not going to like it, I'm afraid... Here it is:
            I have no idea.
            It's interesting to note that most of the experts, when
            designing state machines for C++, have written code generators
            to do it. Of course, most of this goes back to before the days
            of template meta-programming, but as far as I know, no one has
            come up with a better solution. You define a higher level
            language in which you define the transitions, and a "compiler"
            for that language which generates the C++.

            In general, I'd say that this is to be prefered over template
            meta-programming any time the "program" itself didn't need to
            exploit information internal to C++ (like types, etc.). The
            results are almost always more readable.
            If it solves the problem you had, then use it. If it
            does not, let's talk more, perhaps you'll get me to understand what it
            is you hope to accomplish.
            I know that enums are not well suited for your task, they are very low
            level and very limited functionality types. That's why I suggested
            dumping them altogether. You are better off creating a separate type
            for every state set/sequence you need to identify. Each state then
            could be expressed/encoded by a value.
            Enums can have a role to play in a state machine, but they
            certainly aren't a state machine. The "classical" solution, I
            think, is along the lines you suggest: a base class State, and
            each individual state a distinct class deriving from this base,
            with transitions, actions, etc. being handled by virtual
            functions in State.

            You might want to check out http://smc.sourceforge.net/. This
            seems to be derived from Robert Martin's work in the 1990's,
            which is, as far as I know, still the reference. (Note: I've
            not used this tool, and only stumbled upon it looking for
            information about Robert Martin's state machine compiler.)

            --
            James Kanze (GABI Software, from CAI) email:james.kan ze@gmail.com
            Conseils en informatique orientée objet/
            Beratung in objektorientier ter Datenverarbeitu ng
            9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

            Comment

            • Michael DOUBEZ

              #7
              Re: Finding a max for an enum - a template problem

              Kevin a écrit :
              I'm creating a template to support state machines. In doing so, I
              need to pass an enumeration for the number of transitions and a non
              type parameter for the range of the enum (to allow me to allocate an
              array of pointers big enough to hold one entry for each transition).
              [snip]
              >
              I can't find any way to determine the max value of an enum. Most
              previous posts are of the form "You can't do that - please try
              workaround XYZ..." If I must, I could try using #define macros, but
              that just seems to hide the mechanics rather than simplifying them,
              which is a sure recipe for confusion for maintenance programming.
              Did you have a look at the "Variadic Integral Constant" MPL concept in
              boost:


              Instead of passing all enum, it could make sense to allow the
              specification of the enums to use for the states.

              typedef vector_c<states ,ON,OFF,FAIL> base_protocol;
              typedef typedef push_back<base_ protocol,
              integral_c<stat es,TRANSMIT::ty pe
              halfduplex_tran smit;
              typedef typedef push_back<base_ protocol,
              integral_c<stat es,RECEIVE::typ e halfduplex_rece ive;
              typedef vector_c<states ,ON,OFF,FAIL,
              RECEIVE,TRANSMI T,COLLISION> full_duplex;
              //...

              Michael

              Comment

              • Andreas Huber

                #8
                Re: Finding a max for an enum - a template problem

                James Kanze wrote:
                It's interesting to note that most of the experts, when
                designing state machines for C++, have written code generators
                to do it. Of course, most of this goes back to before the days
                of template meta-programming, but as far as I know, no one has
                come up with a better solution.
                I guess it depends on what you mean with "better" here. There are TMP
                FSM solutions:
                - Aleksey Gurtovoy's MPL example
                http://www.mywikinet.com/mpl/fsm_example_25_jul_02.zip shows how a
                simple but fast STT-based FSM can be implemented
                - Boost.Statechar t <http://www.boost.org/libs/statechartprovi des much
                of the UML functionality, including substates and concurrent states
                You define a higher level
                language in which you define the transitions, and a "compiler"
                for that language which generates the C++.
                I believe for quite a few problems there's no longer any need for such
                external (front-end) compilers. C++ itself offers all the necessary
                machinery to do the generation in the language itself, as libraries like
                Boost.Spirit very nicely demostrate.
                In general, I'd say that this is to be prefered over template
                meta-programming any time the "program" itself didn't need to
                exploit information internal to C++ (like types, etc.)
                Which is the case for state machines, isn't it? You usually want to
                write entry-, exit- and transition-actions in C++.

                Regards,

                --
                Andreas Huber

                When replying by private email, please remove the words spam and trap
                from the address shown in the header.

                Comment

                Working...