C ++ 11:如何在行为类似于子类的类内创建枚举类?

时间:2019-02-21 10:33:46

标签: class c++11 data-structures struct enums

为解释我的问题,我在下面发布了一个示例。此格式的代码未经测试,因此可能存在语法错误。由于我必须在集成电路中使用其地址可以重新映射的大量寄存器,因此创建如下所示的结构将非常有用。有创建这些结构的技巧吗?由于此示例无法按我的方式工作,因为foo需要一个Country对象,而Country :: Europe :: Italy作为参数无效。

// I want to create a structure like this
class myClass {
public:
    class Country {

        enum class Europe {
            England,
            France,
            Germany,
            Italy
        };

        enum class Asia {
            China,
            Japan
        };

    };

    // Here I want to make sure, that the method is only
    // called with a Country element and e.g. Italy should
    // behave like a Country object. Actually it should behave
    // as if it is derived from Country.
    int foo(Country c);

};



int main() {
    myClass myC();

    // Exemplary call of the method foo
    myC.foo(myClass::Country::Europe::Italy);
}

3 个答案:

答案 0 :(得分:2)

您无法使用enum class实现目标。但是,您可以将namespace与一组硬编码的constexpr对象一起使用:

struct Country 
{ 
    int _id; 
};

namespace Countries
{ 
    namespace Europe 
    {
        constexpr Country Italy{0};
        constexpr Country France{1};
    };
};

用法:

myC.foo(Countries::Europe::Italy);

答案 1 :(得分:0)

使用寄存器的正确示例和更好的解释会更好。我猜您想从一个寄存器名重新映射到另一个。一条建议:

class Register {
public:
  enum class UserName {
    REG_IO0,
    REG_MEM1
  };
  enum class CPUName {
    REG_INT0,
    REG_INT1
  };
  void setMapping(UserName from, CPUName to); // store the mapping
  CPUName getMapping(UserName name) const; // retrieve the mapping
private:
  std::map<UserName, CPUName> m_registerMap;
};

如果需要,可以存储该寄存器的索引/地址,以实现该类中寄存器的get / set方法。使用模板或针对不同的数据类型重载模板。

答案 2 :(得分:0)

您可以显式地将枚举类型用作函数或构造函数参数,从而限制调用方使用该枚举。 您不能轻易做到的是按照您建议的方式组合多个枚举定义。

您可以编写多个构造函数,分别为欧洲,亚洲等每个枚举构造一个,但是那是可行的,尤其是当您有许多需要将这些枚举作为参数的函数时。

-或-

您可以定义一个大枚举,并为每个子组定义固定值分隔符,因此您可以将枚举值与这些保护值进行比较,以识别子组。如果这样做,您将失去分组。您可以使用c ++ 11常量枚举初始化程序为每个洲的子类构造枚举值成员-但请注意,这些仅适用于c ++ 17中的enum class(因此,我使用了嵌套类技巧来提供成员名称空间的强制实施-在c ++ 17中,您可能有enum class Location-您可以在c ++ 11中编写此代码,但随后不能执行const初始化程序)。这些值遵循上述分隔符规则,但是调用者必须间接通过子类来获取名称。

class Country
{
  class Location {
    enum Value { 
      None =0,
      Europe = 0x0100,
      Asia =   0x0200,
      //etc
    };
  };

  struct Asia {
    const Location::Value Japan { Location::Asia + 1 };
    //etc
  };
  struct Europe {
    const Location::Value UnitedKingdom { Location::Europe + 1 };
    //etc
  };
  // etc
};

那么你就可以拥有

class myClass {
public:
  myClass(Country::Location::Value v);
};

并用

调用
myClass instance(Country::Asia::Japan);

-或-

您可以定义另一个结构,该结构的唯一目的是采用各种枚举并将其转换为大陆和国家索引的一对值。然后,您可以将该结构用作函数参数,并允许从该结构进行自动转换。这意味着您只需执行一次转换,并且代码调用者不会受到影响。您可以使用保护范围,这样就不必显式存储大洲代码,只需原始国家/地区代码在所有枚举中都是唯一的即可。