C ++ Java像枚举头编译器错误 [英] C++ Java like enum header compiler error

查看:55
本文介绍了C ++ Java像枚举头编译器错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以帮助解决以下编译器错误吗?我试图在C ++中创建像枚举之类的Java,并且在Visual Studio 2015中遇到编译器错误。



我正在将这些Java枚举类用作结构体成员我希望sizeof(MessageType)与Value类型相同。我知道这将要求我从类中删除mValueStr成员,但是那样我将无法从字符串中查找值。



Java枚举中真正整洁的东西之一是能够查找枚举类型的能力,这将不胜感激。



使用字符串名称或值。为此,我在枚举类中添加了2个方法,以从这些字符串或值中反向查找枚举。不幸的是,下面的方法显示了波浪线

 静态MessageType valueOf(const int& rVal){
for(const auto& next:getValues()){
if(next == rVal){
~~
return next;
}
}
throw std :: invalid_argument(
Illegal Argument: + rVal);
}

编译器抱怨如下,但我不太清楚: p>

  1> c:\main\dlmu\caclient\udpclient\cmc.h(123):错误C2678:二进制 ==:未找到采用 const MessageType类型的左操作数的运算符(或没有可接受的转换)
1> c:\main\dlmu\caclient\udpclient\cmc.h(123):注意:可以是内置的C ++运算符==((MessageType :: Value,int)
1> c:\main\dlmu\caclient\udpclient\cmc.h(123):注意:在尝试匹配参数列表'(const MessageType,const int)'
1> UDPClient.cpp
1> c:\main\dlmu\caclient\udpclient\cmc.h(123):错误C2678:二进制'==':找不到左手运算符
1>类型为 const MessageType的操作数(或没有可接受的转换)。 c:\程序文件(x86)Windows套件\8.1\包括\guiddef.h(192):注意:可以是'布尔运算符==(const GUID&,const GUID& )'
1> c:\main\dlmu\caclient\udpclient\cmc.h(123):注意:在尝试匹配参数列表'(const MessageType,const int)'

使这种功能起作用的关键是对值类型使用整型强制转换运算符(在这种情况下,这是一个e枚举)值)

  class MessageType {
public:
枚举类值:uint8_t {
undefined = 0,成员系统= 10
};
static const MessageType未定义,成员系统;
//转换语句的整数运算符转换(广播到命名枚举)
内联运算符const Value()const {
return mValue;
}
//设置操作的严格弱排序
内联布尔运算符<(const MessageType& rhs)const {
return mValue< rhs.mValue;
}
//枚举的序列化版本
内联std :: string getStringVal()const {
return mStringVal;
}
静态常量std :: set< MessageType>& getValues(){
static std :: set< MessageType> gValues;
if(gValues.empty()){
gValues.insert(Undefined);
gValues.insert(MemberSystem);
}
返回gValues;
}
静态MessageType valueOf(const int& rVal){
for(const auto& next:getValues()){
if(next == rVal){
接下来返回;
}
}
throw std :: invalid_argument(
Illegal Argument: + rVal);
}
静态MessageType valueOf(const std :: string& rStringVal){
for(const auto& next:getValues()){
if(next.getStringVal()= = rStringVal){
接下来返回;
}
}
throw std :: invalid_argument(
Illegal Argument: + rStringVal);
}
私人:
MessageType(常量值和rValue,常量std :: string& rStringVal)
:mValue(rValue)
,mStringVal(rStringVal)
{}

价值mValue;
std :: string mStringVal;
};

真正的奇怪之处在于,在此定义之前,我有一个类似的类,可以很好地工作而无需弯曲的线条如下:

 类DiscreteStatus {
public:
枚举值:uint8_t {
normaloperation = 0,无计算数据= 1,功能测试= 2,失败警告= 3
};
static const DiscreteStatus NormalOperation,NoComputedData,FunctionalTest,FailureWarning;
//转换语句的整数运算符转换(广播到命名枚举)
内联运算符const Value()const {
return mValue;
}
//设置操作的严格弱顺序
内联布尔运算符<(const DiscreteStatus& rhs)const {
return mValue< rhs.mValue;
}
//枚举的序列化版本
内联std :: string getStringVal()const {
return mStringVal;
}
静态常量std :: set< DiscreteStatus>& getValues(){
static std :: set< DiscreteStatus> gValues;
if(gValues.empty()){
gValues.insert(NormalOperation);
gValues.insert(NoComputedData);
gValues.insert(FunctionalTest);
gValues.insert(FailureWarning);
}
返回gValues;
}
静态DiscreteStatus valueOf(const int& rVal){
for(const auto& next:getValues()){
if(next == rVal){
接下来返回;
}
}
throw std :: invalid_argument(
Illegal Argument: + rVal);
}
静态DiscreteStatus valueOf(const std :: string& rStringVal){
for(const auto& next:getValues()){
if(next.getStringVal()= = rStringVal){
接下来返回;
}
}
throw std :: invalid_argument(
Illegal Argument: + rStringVal);
}
私有:
DiscreteStatus(const Value& rValue,const std :: string& rStringVal)
:mValue(rValue)
,mStringVal(rStringVal)
{}

价值mValue;
std :: string mStringVal;
};

实现文件(CPP)执行静态初始化,如下所示:

  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);


解决方案

在两种情况下,其目的都是调用类型-conversion运算符,以便转换为相应的 Value 类型。



在第一种情况下, 的定义如下:


 枚举类值:uint8_t 


与私有继承更为相似:这是一种已实现的关系。客户端代码不能,并且在您的情况下,不能依赖于 Value 在内部实现为 uint8_t 的事实。



在第二种情况下,如下:


 枚举值:uint8_t 


就像公共继承一样,这意味着客户端代码可以依赖并依赖 Value 实际上是 uint8_t 的事实。这样便可以进行类型转换。



现在,您可以通过将第一个定义更改为 enum值来快速修复代码:uint8_t ,但有人想知道为什么要提供一个带有整数参数的 valueOf 函数。






通常,我强烈建议不要采用这种整体方法。似乎过于复杂,就像通常尝试用语言B编写语言A时一样。



在这种特殊情况下,Java枚举与C ++之间有任何相似之处11个枚举类只是肤浅的。归根结底,从C ++的角度来看,Java枚举是不可复制的类,其静态常量指针指向无法取消引用的垃圾收集实例。您不想用C ++模仿所有这些,您也不能,也不应该。


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");

解决方案

In both cases, the intention is to call the type-conversion operator in order to perform a conversion to the corresponding Value type.

In the first case, you have Value defined like this:

enum class Value : uint8_t

This does not work like public inheritance but is more similar to private inheritance: it's an implemented-in-terms-of relationship. Client code must not and in your case cannot rely on the fact that Value is internally implemented as a uint8_t.

In the second case, however, it's as follows:

enum Value : uint8_t

This can be pictured as something like public inheritance, meaning that client code can rely and depend on the fact that Value is really an uint8_t. The type conversion thus works.

Now, you could quick-fix your code by changing the first definition to enum Value : uint8_t, but one has to wonder why you want to provide a valueOf function with an integer argument anyway. It breaks the abstraction.


Generally, I strongly advise against this whole approach. It seems overly complicated, as is always the case when one attempts to write language A in language B.

In this particular case, any similarities between Java enums and C++11 enum classes are only superficial. At the end of the day, from a C++ perspective, Java enums are non-copyable classes with static constant pointers to garbage-collected instances which cannot be dereferenced. You do not want to emulate all of this in C++, nor can you, nor should you.

这篇关于C ++ Java像枚举头编译器错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆