【问题标题】:Replacing enum with class with int identifiers - doesn't compile用具有 int 标识符的类替换枚举 - 不编译
【发布时间】:2011-10-21 17:47:04
【问题描述】:

我正在做一个项目,我们有一个像这样的标准枚举:

enum Services {
      RequestShower = 611,
      RequestBath = 617,
      RequestShave = 612,
      RequestHaircut = 618
};

但我的老板说最新的 C++ 标准不认为枚举等同于 int,所以建议使用一个有点像这样的类:

class VatelPrivateService {
public:
   static const short
      RequestShower = 611,
      RequestBath = 617,
      RequestShave = 612,
      RequestHaircut = 618;

   static const char* getName(int val);
};

ostream operator<<(ostream& os, VatelPrivateService& service);

好吧,我尝试这样实现:

const char* VatelPrivateService::getName(int id)
{
 #define CASE_NM(rq) case rq: return #rq
   switch(id)
   {
      CASE_NM(RequestShower);
      CASE_NM(RequestBath);
      CASE_NM(RequestShave);
      CASE_NM(RequestHaircut);
   }
#undef CASE_NM
   return "";
}

ostream& operator<<(ostream& os, const VatelPrivateService& service)
{
   os << VatelPrivateService::getName(service);
   return os;
}

然后这样称呼它:

cout << "item: " << VatelPrivateService::RequestShower << endl;

但上面的代码无法编译 - 获取: 错误 C2664:“VatelPrivateService::getName”:无法将参数 1 从“const VatelPrivateService”转换为“int”

希望你能看到我的意图。我该如何解决这个问题?

安格斯

【问题讨论】:

    标签: c++


    【解决方案1】:

    最新的 C++ 标准不认为枚举等同于 int

    enum 的规范没有改变:枚举数仍然可以隐式转换为其基础整数类型。

    C++11 增加了一个新概念enum class,它是一个“强类型和作用域的枚举”。这种新的枚举类型不允许将其枚举数隐式转换为基础整数类型(不过,您可以使用static_cast 显式强制转换)。

    如果您想编写自己的范围枚举,提供类似于enum class 的语义和行为,但可在不支持enum class 的编译器上使用,您应该阅读Howard Hinnant's answer to this other question,其中他提供了一个工作示例。

    【讨论】:

    • 你甚至可以指定枚举现在使用的底层类型。
    【解决方案2】:

    您的VatelPrivateService(实际上)是一个命名空间,而不是一个类,因为它没有数据。这意味着ostream operator&lt;&lt;(ostream&amp; os, VatelPrivateService&amp; service); 不会做太多事情,因为传递给 ostream 的服务没有数据。您的值都是unsigned short 类型,这意味着您应该拥有ostream operator&lt;&lt;(ostream&amp; os, unsigned short service);。除了已经定义的。您需要使 VatelPrivateService 成为一个实际的值类型类,因此它拥有一个值以使这成为可能。

    当然,真正的答案是你的老板错了,枚举会像往常一样工作。不要这样做。

    【讨论】:

      【解决方案3】:

      您的运算符重载接受 VatelPrivateService 的实例作为参数,或者更确切地说是对一个实例的 const 引用。但是在VatelPrivateService 中定义的成员,例如您传递给coutVatelPrivateService::RequestShowershort 类型,因此即使您更改了operator&lt;&lt; 重载的实现以便它编译它仍然不会调用VatelPrivateService::RequestShower 参数,因为这只是一个简单的short

      枚举不等同于 int,但通常可以隐式转换为 1,如果不是,您可以使用 static_cast 进行转换。使用枚举实际上是我能想到的最简单的解决方案,而且我会使用的解决方案可以在需要时将其转换为 int。

      【讨论】:

        【解决方案4】:

        试试

        class VatelPrivateSer
        {
          private:
            const int value;
            VatelPrivateSer(int value) : value(value) {};
          public:
            static const VatelPrivateSer RequestBath() { return 617; }
            static const VatelPrivateSer RequestHaircut() { return 618; }
            static const VatelPrivateSer RequestShave() { return 612; }
            static const VatelPrivateSer RequestShower() { return 611; }
            int AsInt() const { return value; }
        };
        

        您可以随时使用我的网页http://well-spun.co.uk/code_templates/enums.php :-)

        【讨论】:

        • 我可能会超载operator int(),因为他们似乎希望enums 与整数“等效”。
        • 同时创建“值”static const VatelPrivateSer(不是函数),这样就不需要括号了。
        • Scott Meyers (2nd edition Effective C++) - item 46 是模板的来源。
        • 我可以理解为什么 Scott Meyers 会推荐反对 operator int(),除了 OP 暗示他希望在这种情况下使用该功能。 Scott Meyers 是否证明了为什么“值”是函数而不是静态对象?可能是这样,如果您尝试获取地址,通常会出错?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-10
        • 2021-08-02
        • 1970-01-01
        • 2016-03-05
        • 2012-09-15
        相关资源
        最近更新 更多