Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emulating a Java Enum in C++

I have been porting an application that I wrote some time ago from Java over to C++. One thing that I quickly realized was that Java's rich Enum's (which were introduced in Java 5) were far superior to those provided in C++. C++0x, and later C++11's 'Strongly typed enums' (aka enum classes) still do not provide the richness that Java Enums provide, and I could not find anything to emulate this facility here.

I set out to try to emulate some of the features as stand along classes, and I would like some help to implement this, perhaps using templates if appropriate (it just seems like there should be a more generic way to implement this). You will see that the ability to look up a particular Enum through a string name is rather verbosely implemented - (this is an emulation of the Java ENUM's valueOf(String str) method - it works - but I am sure that it is far from optimal. The way I have implemented the Enum instances are using static const instances of within the class - I found this somewhere on Stack Overflow - but I cannot recall exactly where - sorry.

FYI the the application is an NMEA String parser, and here are a few of the more interesting Enum classes:

Here is the Header

#ifndef _NMEASentence_h_
#define _NMEASentence_h_

// SYSTEM INCLUDES
#include <stdint.h>
#include <string>

// APPLICATION INCLUDES
// DEFINES
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS

 /**
 *  Name:  NMEASentence
 */
class NMEASentence
{
public:
    static const int MAX_LEN;
    static const char START;
    static const char CKSM_DELIM;
    static const char CR;
    static const char LF;

    NMEASentence(
        const std::string rPrefix,
        const std::string& rParams)
        : mPrefix(rPrefix)
        , mParams(rParams)
    {};

    // make the class abstract
    virtual ~NMEASentence() = 0;

protected:
    std::string mPrefix;
    std::string mParams;
};

#endif // _NMEASentence_h_

Here is the CPP

// SYSTEM INCLUDES
// APPLICATION INCLUDES
#include "vcdu/NMEASentence.h"

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
const int NMEASentence::MAX_LEN = 82;
const char NMEASentence::START = '$';
const char NMEASentence::CKSM_DELIM = '*';
const char CR = '\r';
const char LF = '\n';    

// implementation of the pure virtual dtor allowed
// its a trick to allow class to be abstract
NMEASentence::~NMEASentence()
{};

Here is a subclass of the generic NMEASentence class

#ifndef _CDUMessage_h_
#define _CDUMessage_h_

// SYSTEM INCLUDES
//#include <...>

// APPLICATION INCLUDES
#include "vcdu/NMEASentence.h"
#include "vcdu/CDUEnumConstants.h"

// DEFINES
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS

/**
 * CDUMessage
 */
class CDUMessage : public NMEASentence
{
public:
    /**
     * 5 classifications of message types, The type specifies the
     * number and type of each parameter
     */
    typedef enum CDUMessageSubType {
        Alive,
        Display,
        XYDisplay,
        Status,
        Keyboard,
        Configuration
    } CDUMessageSubType;

    /**
     * enumeration of the supported message types & their arg count
     */
    static class CDUMessageType {
    public:
        static const CDUMessageType CDUAlive;
        // the following 3 messages are associated with the title line
        static const CDUMessageType CDUDisplayDataStatusBlock;
        static const CDUMessageType CDUDisplayTitle;
        static const CDUMessageType CDUDisplayPageNumber;
        // these messages are associated with the active display area
        static const CDUMessageType CDUDisplayScratchPad;
        static const CDUMessageType CDUDisplayLS1Text;
        static const CDUMessageType CDUDisplayLS2Text;
        static const CDUMessageType CDUDisplayLS3Text;
        static const CDUMessageType CDUDisplayLS4Text;
        static const CDUMessageType CDUDisplayLS5Text;
        static const CDUMessageType CDUDisplayLS6Text;
        static const CDUMessageType CDUDisplayLS1SText;
        static const CDUMessageType CDUDisplayLS2SText;
        static const CDUMessageType CDUDisplayLS3SText;
        static const CDUMessageType CDUDisplayLS4SText;
        static const CDUMessageType CDUDisplayLS5SText;
        static const CDUMessageType CDUDisplayLS6SText;
        static const CDUMessageType CDUDisplayRS1Text;
        static const CDUMessageType CDUDisplayRS2Text;
        static const CDUMessageType CDUDisplayRS3Text;
        static const CDUMessageType CDUDisplayRS4Text;
        static const CDUMessageType CDUDisplayRS5Text;
        static const CDUMessageType CDUDisplayRS6Text;
        static const CDUMessageType CDUDisplayRS1SText;
        static const CDUMessageType CDUDisplayRS2SText;
        static const CDUMessageType CDUDisplayRS3SText;
        static const CDUMessageType CDUDisplayRS4SText;
        static const CDUMessageType CDUDisplayRS5SText;
        static const CDUMessageType CDUDisplayRS6SText;
        // this is a special message to clear the screen buffer
        static const CDUMessageType CDUDisplayCLS;
        static const CDUMessageType CDUDisplayPutString;
        static const CDUMessageType CDUStatus;
        static const CDUMessageType CDUKeyboard;
        static const CDUMessageType CDUSet;
        static const CDUMessageType CDUGet;

        inline std::string getPrefix() const {
            return mPrefix;
        }

        inline CDUMessageSubType getMesageSubType() const {
            return mSubType;
        }

        inline virtual int getTextRowIndex() const {
            return mTextRowIndex;
        }

        inline JustifyStyle getJustifyStyle() const {
            return mJustifyStyle;
        }

        static std::vector<CDUMessageType>& getValues() {
            static std::vector<CDUMessageType> gValues;
            if (gValues.empty()) {
                gValues.push_back(CDUAlive);
                gValues.push_back(CDUDisplayDataStatusBlock);
                gValues.push_back(CDUDisplayTitle);
                gValues.push_back(CDUDisplayPageNumber);
                gValues.push_back(CDUDisplayScratchPad);
                gValues.push_back(CDUDisplayLS1Text);
                gValues.push_back(CDUDisplayLS2Text);
                gValues.push_back(CDUDisplayLS3Text);
                gValues.push_back(CDUDisplayLS4Text);
                gValues.push_back(CDUDisplayLS5Text);
                gValues.push_back(CDUDisplayLS6Text);
                gValues.push_back(CDUDisplayLS1SText);
                gValues.push_back(CDUDisplayLS2SText);
                gValues.push_back(CDUDisplayLS3SText);
                gValues.push_back(CDUDisplayLS4SText);
                gValues.push_back(CDUDisplayLS5SText);
                gValues.push_back(CDUDisplayLS6SText);
                gValues.push_back(CDUDisplayRS1Text);
                gValues.push_back(CDUDisplayRS2Text);
                gValues.push_back(CDUDisplayRS3Text);
                gValues.push_back(CDUDisplayRS4Text);
                gValues.push_back(CDUDisplayRS5Text);
                gValues.push_back(CDUDisplayRS6Text);
                gValues.push_back(CDUDisplayRS1SText);
                gValues.push_back(CDUDisplayRS2SText);
                gValues.push_back(CDUDisplayRS3SText);
                gValues.push_back(CDUDisplayRS4SText);
                gValues.push_back(CDUDisplayRS5SText);
                gValues.push_back(CDUDisplayRS6SText);
                gValues.push_back(CDUDisplayCLS);
                gValues.push_back(CDUDisplayPutString);
                gValues.push_back(CDUStatus);
                gValues.push_back(CDUKeyboard);
                gValues.push_back(CDUSet);
                gValues.push_back(CDUGet);
            }
            return gValues;
        }
    private:
        CDUMessageType(const std::string& rPrefix,
            const CDUMessageSubType& rSubType,
            const JustifyStyle& rJustifyStyle,
            const int& rTextRowIndex)
            : mPrefix (rPrefix)
            , mSubType (rSubType)
            , mJustifyStyle(rJustifyStyle)
            , mTextRowIndex(rTextRowIndex)
        {}

        std::string mPrefix;
        CDUMessageSubType mSubType;
        JustifyStyle mJustifyStyle;
        int mTextRowIndex;
    };

    CDUMessageType getMessageType() const {
        return mMessageType;
    };

    virtual ~CDUMessage(){};
protected:
    /**
     * Alternative Simplified Constructor
     * @param aMessageType
     * @param aParams
     */
    CDUMessage(const CDUMessageType& rMessageType, const std::string& rParams)
        : NMEASentence (rMessageType.getPrefix(), rParams)
        , mMessageType (rMessageType)
    {};

    CDUMessageType mMessageType;
};

#endif // _CDUMessage_h_

And the corresponding CPP

// SYSTEM INCLUDES
//#include <...>

// APPLICATION INCLUDES
#include "vcdu/CDUMessage.h"

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
// this is the heartbeat message (not associated with any line => -1 for last paramter)
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUAlive ("PCDUALIVE", CDUMessage::Alive, JustifyStyle::Left, -1);

// the following 3 messages are associated with the title line
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayDataStatusBlock("PCDUDSB", CDUMessage::Display,  JustifyStyle::Left, 0);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayTitle("PCDUTIT", CDUMessage::Display, JustifyStyle::Center, 0);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayPageNumber("PCDUPGE", CDUMessage::Display, JustifyStyle::Right, 0);

// these messages are associated with the active display area
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayScratchPad("PCDUSPD", CDUMessage::Display,  JustifyStyle::Left, 13);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS1Text("PCDUL1T", CDUMessage::Display,  JustifyStyle::Left, 2);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS2Text("PCDUL2T", CDUMessage::Display,  JustifyStyle::Left, 4);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS3Text("PCDUL3T", CDUMessage::Display,  JustifyStyle::Left, 6);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS4Text("PCDUL4T", CDUMessage::Display,  JustifyStyle::Left, 8);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS5Text("PCDUL5T", CDUMessage::Display,  JustifyStyle::Left, 10);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS6Text("PCDUL6T", CDUMessage::Display,  JustifyStyle::Left, 12);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS1SText("PCDUL1S", CDUMessage::Display,  JustifyStyle::Left, 1);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS2SText("PCDUL2S", CDUMessage::Display,  JustifyStyle::Left, 3);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS3SText("PCDUL3S", CDUMessage::Display,  JustifyStyle::Left, 5);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS4SText("PCDUL4S", CDUMessage::Display,  JustifyStyle::Left, 7);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS5SText("PCDUL5S", CDUMessage::Display,  JustifyStyle::Left, 9);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayLS6SText("PCDUL6S", CDUMessage::Display,  JustifyStyle::Left, 11);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS1Text("PCDUR1T", CDUMessage::Display, JustifyStyle::Right, 2);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS2Text("PCDUR2T", CDUMessage::Display, JustifyStyle::Right, 4);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS3Text("PCDUR3T", CDUMessage::Display, JustifyStyle::Right, 6);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS4Text("PCDUR4T", CDUMessage::Display, JustifyStyle::Right, 8);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS5Text("PCDUR5T", CDUMessage::Display, JustifyStyle::Right, 10);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS6Text("PCDUR6T", CDUMessage::Display, JustifyStyle::Right, 12);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS1SText("PCDUR1S", CDUMessage::Display, JustifyStyle::Right, 1);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS2SText("PCDUR2S", CDUMessage::Display, JustifyStyle::Right, 3);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS3SText("PCDUR3S", CDUMessage::Display, JustifyStyle::Right, 5);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS4SText("PCDUR4S", CDUMessage::Display, JustifyStyle::Right, 7);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS5SText("PCDUR5S", CDUMessage::Display, JustifyStyle::Right, 9);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayRS6SText("PCDUR6S", CDUMessage::Display, JustifyStyle::Right, 11);

// these messages are not associated with a paricular line# which is why we specify -1 for the last parameter
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayCLS("PCDUCLS", CDUMessage::Display,  JustifyStyle::Left, -1);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUDisplayPutString("PCDUPUTS", CDUMessage::XYDisplay,  JustifyStyle::None, -1);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUStatus("PCDUSID", CDUMessage::Status,  JustifyStyle::Left, -1);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUKeyboard("PCDUKEY", CDUMessage::Keyboard,  JustifyStyle::Left, -1);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUSet("PCDUSETV", CDUMessage::Configuration,  JustifyStyle::Left, -1);
const CDUMessage::CDUMessageType CDUMessage::CDUMessageType::CDUGet("PCDUGETV", CDUMessage::Configuration, JustifyStyle::Left, -1);

And just to show the general pattern of how the Enums are used here we have some other Enum C++ classes that I needed to use throughout the application. They all look pretty similar and I cannot help but feel that there must be an easier less verbose way of implementing this. Any help or ideas would be really welcome.

class JustifyStyle {
public:
    static const JustifyStyle Left, Center, Right, None;
    inline std::string getName() const {
        return mName;
    }
private:
    JustifyStyle(const std::string& rName) 
        : mName(rName)
    {}
    std::string mName;
};

class FontSize {
public:
    static const FontSize F1, F2, F3, F4, F5, F6;
    inline std::string getName() const {
        return mName;
    }
    static std::vector<FontSize>& getValues() {
        static std::vector<FontSize> gValues;
        if (gValues.empty()) {
            gValues.push_back(F1);
            gValues.push_back(F2);
            gValues.push_back(F3);
            gValues.push_back(F4);
            gValues.push_back(F5);
            gValues.push_back(F6);
        }
        return gValues;
    }
private:
    FontSize(const std::string& rName) 
        : mName(rName)
    {}
    std::string mName;
};

class FontStyle {
public:
    static const FontStyle S, B, I, U, N;
    inline std::string getName() const {
        return mName;
    }
    static std::vector<FontStyle>& getValues() {
        static std::vector<FontStyle> gValues;
        if (gValues.empty()) {
            gValues.push_back(S);
            gValues.push_back(B);
            gValues.push_back(I);
            gValues.push_back(U);
            gValues.push_back(N);
        }
        return gValues;
    }
    inline bool operator<(const FontStyle& rhs) const {
        return mName < rhs.mName;
    }
private:
    FontStyle(const std::string& rName) 
        : mName(rName)
    {}
    std::string mName;
};

class FontColor {
public:
    static const FontColor BLACK, CYAN, RED, YELLOW, GREEN, MAGENTA, AMBER, WHITE;
    inline int getValue() const {
        return mValue;
    }
    inline std::string getValueStr() const {
        return UtlStringUtils::integerToString(mValue);
    }
    static std::vector<FontColor>& getValues() {
        static std::vector<FontColor> gValues;
        if (gValues.empty()) {
            gValues.push_back(BLACK);
            gValues.push_back(CYAN);
            gValues.push_back(RED);
            gValues.push_back(YELLOW);
            gValues.push_back(GREEN);
            gValues.push_back(MAGENTA);
            gValues.push_back(AMBER);
            gValues.push_back(WHITE);
        }
        return gValues;
    }
private:
    // constructor
    FontColor(const int& rValue) 
        : mValue(rValue)
    {}
    int mValue;
};

class CDUFontChar {
public:
    // constructor
    CDUFontChar (
        const char cduChar = '\0',
        const FontSize& rSize = FontSize::F3,
        const std::set<FontStyle>& rStyles = std::set<FontStyle>(),
        const FontColor& rColor = FontColor::WHITE) 
        : mCDUChar (cduChar)
        , mSize (rSize)
        , mFontStyles(rStyles)
        , mColor(rColor)
    {}

    inline char getCDUChar() const {
        return mCDUChar;
    }

    inline FontSize getSize() const {
        return mSize;
    }

    inline std::set<FontStyle> getStyles() const {
        return mFontStyles;
    }

    inline FontColor getColor() const {
        return mColor;
    }
private:
    char mCDUChar;
    FontSize mSize;
    std::set<FontStyle> mFontStyles;
    FontColor mColor;
};
like image 448
johnco3 Avatar asked Sep 04 '12 18:09

johnco3


2 Answers

Basically, a Java enum is a language feature meant to cross the bridge between the good practice of a constant and the bad practice or antipattern of a singleton. C++ makes enum into boring integer constants and Java makes them into fully object oriented singletons but hopes the developer will keep their const-roots in mind. So yes, you are exactly correct - the way to port over is to use C++ global constants. Strictly speaking Java enums do not have to be constants, e.g. they can have non-final fields, but I would (and think "this is") regard this as bad practice, so similarly, all the methods in your C++ enums should be semantically const.

like image 138
djechlin Avatar answered Nov 02 '22 15:11

djechlin


I've had a chance to refine the approach I have been using to simulate Java like enums in C++ since I posed the question to stack overflow. The code shown below (in the header and implementation cpp file) along with a snippet of code showing how the enums can be used in a switch statement are what I ended up using throughout my code. The subtleties lie in the use of the integral cast operator (which in this case are through the use of the Value custom operator used as follows.

// integral operator cast for switch statements (cast to named enum)
inline operator const Value() const {
    return mValue;
}

In the header file CDUEnumConstants.h:

#ifndef _cduEnumConstants_h_
#define _cduEnumConstants_h_

// SYSTEM INCLUDES
#include <set>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>

// APPLICATION INCLUDES
#include "util/UtlExceptions.h"
#include "util/UtlStringUtils.h"

// DEFINES
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
class Annunciator {
public:
    enum Value {
        // these are all undefined in the discrete sense
        undefined=-1, power=-2, fail=-3,
        // these are discrete bits
        exec=(1<<6), dspy=(1<<7), msg=(1<<8), ofst=(1<<9)
    };
    static const Annunciator AnnunciatorUNDEFINED;
    static const Annunciator AnnunciatorPOWER;
    static const Annunciator AnnunciatorFAIL;
    static const Annunciator AnnunciatorEXEC;
    static const Annunciator AnnunciatorDSPY;
    static const Annunciator AnnunciatorMSG;
    static const Annunciator AnnunciatorOFST;
    // used to store in a set
    inline bool operator<(const Annunciator& rhs) const {
        return mValue < rhs.mValue;
    }
    // used for comparisons
    inline bool operator==(const Annunciator& rhs) const {
        return mValue == rhs.mValue;
    }
    inline bool supported() const {
        return mValue > 0;
    }
    // integral operator cast for switch statements (cast to named enum)
    inline operator const Value() const {
        return mValue;
    }

    inline std::string getStringVal() const {
        return mStringVal;
    }

    static const std::set<Annunciator>& getValues() {
        static std::set<Annunciator> gValues;
        if (gValues.empty()) {
            gValues.insert(AnnunciatorUNDEFINED);
            gValues.insert(AnnunciatorPOWER);
            gValues.insert(AnnunciatorFAIL);
            gValues.insert(AnnunciatorEXEC);
            gValues.insert(AnnunciatorDSPY);
            gValues.insert(AnnunciatorMSG);
            gValues.insert(AnnunciatorOFST);
        }
        return gValues;
    }
    static Annunciator valueOf(const std::string& rStringVal) {
        for (const auto& next : getValues()) {
            if (next.getStringVal() == rStringVal) {
                return next;
            }
        }
        throw new UtlIllegalArgumentException(
            "Illegal Argument: " + rStringVal);
    }
private:
    Annunciator(const Value& rValue, const std::string& rStringVal)
        : mValue(rValue)
        , mStringVal(rStringVal)
    {}
    Value mValue;
    std::string mStringVal;
};


// FORWARD DECLARATIONS

// Extendable in the future
class CDUVariable {
public:
    enum Value {
        baud, firmware, type, serial
    };
    static const CDUVariable Baud, Firmware, Type, Serial;
    // used to store in a set
    inline bool operator<(const CDUVariable& rhs) const {
        return mValue < rhs.mValue;
    }
    // used for comparisons
    inline bool operator==(const CDUVariable& rhs) const {
        return mValue == rhs.mValue;
    }
    // integral operator cast for switch statements (cast to named enum)
    inline operator const Value() const {
        return mValue;
    }
    inline std::string getStringVal() const {
        return mStringVal;
    }
    static const std::set<CDUVariable>& getValues() {
        static std::set<CDUVariable> gValues;
        if (gValues.empty()) {
            gValues.insert(Baud);
            gValues.insert(Firmware);
            gValues.insert(Type);
            gValues.insert(Serial);
        }
        return gValues;
    }
    static CDUVariable valueOf(const std::string& rStringVal) {
        for (const auto& next : getValues()) {
            if (next.getStringVal() == rStringVal) {
                return next;
            }
        }
        throw new UtlIllegalArgumentException(
            "Illegal Argument: " + rStringVal);
    }
private:
    CDUVariable(const Value& rValue, const std::string& rStringVal)
        : mValue(rValue)
        , mStringVal(rStringVal)
    {}
    Value mValue;
    std::string mStringVal;
};

#endif // _cduEnumConstants_h_

and in the implementation CDUEnumConstants.cpp file where the initial values of the enums are initialized.

const Annunciator Annunciator::AnnunciatorUNDEFINED(Annunciator::undefined, "UNDEFINED");
const Annunciator Annunciator::AnnunciatorPOWER(Annunciator::power, "POWER");
const Annunciator Annunciator::AnnunciatorFAIL(Annunciator::fail, "FAIL");
const Annunciator Annunciator::AnnunciatorEXEC(Annunciator::exec, "EXEC");
const Annunciator Annunciator::AnnunciatorDSPY(Annunciator::dspy, "DSPY");
const Annunciator Annunciator::AnnunciatorMSG(Annunciator::msg, "MSG");
const Annunciator Annunciator::AnnunciatorOFST(Annunciator::ofst, "OFST");

const CDUVariable CDUVariable::Baud(CDUVariable::baud, "0");
const CDUVariable CDUVariable::Firmware(CDUVariable::firmware, "1");
const CDUVariable CDUVariable::Type(CDUVariable::type, "2");
const CDUVariable CDUVariable::Serial(CDUVariable::serial, "3");

Now to use the CDUVariable enum in a switch statement in user code (ignore the other method details), use the following.

std::unique_ptr<EngravityMessage>
VCDUManager::getConfigValue(
    const CDU_ID& rCduID,
    const std::unique_ptr<EngravityMessage>& rVarNameMessage)
{
    EngravityConfigMessage* pVariableName =
        static_cast<EngravityConfigMessage*>(rVarNameMessage.get());
    gpLogManager->add(FAC_PROCESS, PRI_NOTICE,
        "CDU_%d: getConfigValue\n", rCduID);
    CDUVariable variable = pVariableName->getCDUVariable();
    std::unique_ptr<EngravityMessage> variableValue;
    switch (variable) {
    case CDUVariable::baud:
        variableValue = std::unique_ptr<EngravityMessage>(
            new EngravityConfigMessage (
                EngravityMessageType::SetV, variable, "38400"));
        break;
    case CDUVariable::firmware:
        variableValue = std::unique_ptr<EngravityMessage>(
            new EngravityConfigMessage (
                EngravityMessageType::SetV, variable, "1.04"));
        break;
    case CDUVariable::type:
        variableValue = std::unique_ptr<EngravityMessage>(
            new EngravityConfigMessage (
                EngravityMessageType::SetV, variable, "737-NG"));
        break;
    case CDUVariable::serial:
        variableValue = std::unique_ptr<EngravityMessage>(
            new EngravityConfigMessage (
                EngravityMessageType::SetV, variable, "0074"));
        break;
    default:
        break;
    }
    return variableValue;
}

I provided 2 examples of Enums for 2 reasons, firstly I wanted to show how to look up an Enum value from a string - which is optimized to use a sorted set, and secondly, the pattern here seems to hint at template programming - but I didn't get a chance to implement it as a template - actually I am not sure if it can.

like image 39
johnco3 Avatar answered Nov 02 '22 17:11

johnco3