C ++ 11: Как создать класс enum внутри класса, который ведет себя как подкласс? - PullRequest
0 голосов
/ 21 февраля 2019

Чтобы объяснить мою проблему, я разместил пример ниже.Код в этой форме не тестируется, поэтому в нем может быть какая-то синтаксическая ошибка.Поскольку мне приходится работать с множеством регистров в интегральной схеме с их адресами, которые можно переназначать, было бы очень полезно создать структуры, подобные приведенным ниже.Есть ли какая-то хитрость для создания этих структур?Поскольку этот пример не работает так, как я хочу, потому что 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 голосов
/ 21 февраля 2019

Правильный пример использования регистров и лучшего объяснения был бы лучше.Я предполагаю, что вы хотите переназначить одно имя регистра в другое.Предложение:

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 для регистров в этом классе, если вы храните индексы / адреса регистров.Используйте шаблоны или перегрузите их для разных типов данных.

0 голосов
/ 21 февраля 2019

Вы можете явно использовать тип enum в качестве аргумента функции или конструктора, ограничивая вызывающую функцию этим перечислением.То, что вы не можете сделать тривиально, это объединить несколько определений перечислений так, как вы предлагаете.

Вы можете написать несколько конструкторов, по одному для каждого из перечислений Европа, Азия и т. Д., Но это будет работатьособенно если у вас есть ряд функций, которые должны принимать эти перечисления в качестве аргументов.

- ИЛИ -

Вы можете определить одно большое перечисление и определить фиксированные разделители значений для каждой подгруппы., так что вы можете сравнить значение перечисления с этими защитными значениями, чтобы определить подгруппу.Вы потеряете подгруппу, если вы это сделаете.Вы могли бы использовать инициализаторы константного перечисления c ++ 11 для создания членов-значений перечисления в подклассах для каждого континента - но учтите, что они доступны только для enum class из c ++ 17 (поэтому я использую трюк с вложенным классом для предоставления пространства имен членапринудительное выполнение - в 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);

- ИЛИ -

Вы можете определить другоеСтруктура, единственная цель которой состоит в том, чтобы взять различные перечисления и преобразовать их в пару значений для индекса континента и страны.Затем вы можете использовать эту структуру в качестве параметра функции и разрешить автоматическое преобразование из этой структуры.Это означает, что вы выполняете преобразование только один раз, и вызывающие к вашему коду не влияютВы можете использовать защитные диапазоны так, чтобы вам не нужно было явно хранить код континента, просто необработанный номер страны был бы уникальным для всех ваших перечислений.

0 голосов
/ 21 февраля 2019

Вы не можете использовать 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);
...