Could someone help with the following compiler error? I am trying to create a Java like enums in C++ and I am getting compiler errors in Visual Studio 2015.
I am using these Java like Enum classes as members of a struct and I would like the sizeof(MessageType) to be the same as the Value type. I know that this will require that I remove the mValueStr member from the class, however then I will not be able to look up the value from a string. Any suggestions on how I might be able to achieve that would be greatly appreciated.
One of the really neat things in the Java Enums is the ability to look up the enum type using the String name or value. To that end I added 2 methods to my enum classes to reverse look up the enums from these strings or values. Unfortunately the method below has the squiggly lines indicated
static MessageType valueOf(const int& rVal) {
for (const auto& next : getValues()) {
if (next == rVal) {
~~
return next;
}
}
throw std::invalid_argument(
"Illegal Argument: " + rVal);
}
and the compiler complains as follows and I cannot quite figure it out:
1>c:\main\dlmu\caclient\udpclient\cmc.h(123): error C2678: binary '==': no operator found which takes a left-hand operand of type 'const MessageType' (or there is no acceptable conversion)
1> c:\main\dlmu\caclient\udpclient\cmc.h(123): note: could be 'built-in C++ operator==(MessageType::Value, int)'
1> c:\main\dlmu\caclient\udpclient\cmc.h(123): note: while trying to match the argument list '(const MessageType, const int)'
1> UDPClient.cpp
1>c:\main\dlmu\caclient\udpclient\cmc.h(123): error C2678: binary '==': no operator found which takes a left-hand operand of type 'const MessageType' (or there is no acceptable conversion)
1> c:\program files (x86)\windows kits\8.1\include\shared\guiddef.h(192): note: could be 'bool operator ==(const GUID &,const GUID &)'
1> c:\main\dlmu\caclient\udpclient\cmc.h(123): note: while trying to match the argument list '(const MessageType, const int)'
The key to getting this type of functionality working is to use the integral cast operator to a Value type (which in this case is an e bit enum value)
class MessageType {
public:
enum class Value : uint8_t {
undefined = 0, membersystem = 10
};
static const MessageType Undefined, MemberSystem;
// integral operator cast for switch statements (cast to named enum)
inline operator const Value() const {
return mValue;
}
// strict weak ordering for set ops
inline bool operator<(const MessageType& rhs) const {
return mValue < rhs.mValue;
}
// serialized version of the enum
inline std::string getStringVal() const {
return mStringVal;
}
static const std::set<MessageType>& getValues() {
static std::set<MessageType> gValues;
if (gValues.empty()) {
gValues.insert(Undefined);
gValues.insert(MemberSystem);
}
return gValues;
}
static MessageType valueOf(const int& rVal) {
for (const auto& next : getValues()) {
if (next == rVal) {
return next;
}
}
throw std::invalid_argument(
"Illegal Argument: " + rVal);
}
static MessageType valueOf(const std::string& rStringVal) {
for (const auto& next : getValues()) {
if (next.getStringVal() == rStringVal) {
return next;
}
}
throw std::invalid_argument(
"Illegal Argument: " + rStringVal);
}
private:
MessageType(const Value& rValue, const std::string& rStringVal)
: mValue(rValue)
, mStringVal(rStringVal)
{}
Value mValue;
std::string mStringVal;
};
The really strange thing is that right before this definition I have a similar class that works fine without squiggly lines as follows:
class DiscreteStatus {
public:
enum Value : uint8_t {
normaloperation = 0, nocomputeddata = 1, functionaltest = 2, failurewarning = 3
};
static const DiscreteStatus NormalOperation, NoComputedData, FunctionalTest, FailureWarning;
// integral operator cast for switch statements (cast to named enum)
inline operator const Value() const {
return mValue;
}
// strict weak ordering for set ops
inline bool operator<(const DiscreteStatus& rhs) const {
return mValue < rhs.mValue;
}
// serialized version of the enum
inline std::string getStringVal() const {
return mStringVal;
}
static const std::set<DiscreteStatus>& getValues() {
static std::set<DiscreteStatus> gValues;
if (gValues.empty()) {
gValues.insert(NormalOperation);
gValues.insert(NoComputedData);
gValues.insert(FunctionalTest);
gValues.insert(FailureWarning);
}
return gValues;
}
static DiscreteStatus valueOf(const int& rVal) {
for (const auto& next : getValues()) {
if (next == rVal) {
return next;
}
}
throw std::invalid_argument(
"Illegal Argument: " + rVal);
}
static DiscreteStatus valueOf(const std::string& rStringVal) {
for (const auto& next : getValues()) {
if (next.getStringVal() == rStringVal) {
return next;
}
}
throw std::invalid_argument(
"Illegal Argument: " + rStringVal);
}
private:
DiscreteStatus(const Value& rValue, const std::string& rStringVal)
: mValue(rValue)
, mStringVal(rStringVal)
{}
Value mValue;
std::string mStringVal;
};
The implementation file (CPP) performs the static initialization as follows:
const DiscreteStatus DiscreteStatus::NormalOperation(DiscreteStatus::Value::normaloperation, "NML");
const DiscreteStatus DiscreteStatus::NoComputedData(DiscreteStatus::Value::nocomputeddata, "NCD");
const DiscreteStatus DiscreteStatus::FunctionalTest(DiscreteStatus::Value::functionaltest, "FT");
const DiscreteStatus DiscreteStatus::FailureWarning(DiscreteStatus::Value::failurewarning, "FW");
const MessageType MessageType::Undefined(MessageType::Value::undefined, "Undefined");
const MessageType MessageType::MemberSystem(MessageType::Value::membersystem, "MemberSystem");