Подтвердить что ты не робот

Создание составного типа из двух классов enum, готовых для STL-карты

Я хотел бы создать составной тип из двух enum classes.

enum class Color {RED, GREEN, BLUE};
enum class Shape {SQUARE, CIRCLE, TRIANGLE};

class Object {
  Color color;
  Shape shape;
public:
};

Чтобы использовать Object в контейнере STL, таком как std::map<>, мне нужно будет перегрузить оператор меньшего размера. Однако, чтобы сгладить оба класса перечисления в один линейный индекс, мне как-то нужно количество элементов (NoE) классов перечисления:

friend bool operator< (const Object &lhs, const Object &rhs) {
  return NoE(Shape)*lhs.color+lhs.shape < NoE(Shape)*rhs.color+rhs.shape;
}

Как это можно сделать без ввода одинаковой информации (количество элементов) в двух местах в программе в приятной форме? (Хороший способ означает FIRST_ELEMENT, LAST_ELEMENT, препроцессорную магию и т.д.)

Вопрос (Число элементов в перечислении) аналогичен, но не адресует enum classes.

Я хотел бы знать, как наилучшим образом реализовать этот тип составных типов в С++ 11. Является ли определение класса enum достаточно сильным или необходимо сказать:?

enum class Color {RED=0, GREEN=1, BLUE=2};
enum class Shape {SQUARE=0, CIRCLE=1, TRIANGLE=2};
4b9b3361

Ответ 1

Как прокомментировано и как уже сказано другими, отдайте предпочтение либо Shape, либо Color в operator< и сравните только другое, если первое равно. Альтернативная реализация для operator< с помощью std::tie:

#include <tuple>
friend bool operator<(const Object& lhs, const Object& rhs)
{
    return std::tie(lhs.color, lhs.shape) < std::tie(rhs.color, rhs.shape);
}

Ответ 2

Рассмотрим просто std::tuple<Color, Shape> как "составное перечисление". Это будет поставляться с операторами сравнения, которые уже определены для вас, используя порядок словарей. Например, действительный код:

bool b = std::make_tuple(Color::RED, Shape::CIRCLE)
       < std::make_tuple(Color::GREEN, Shape::SQUARE);

Ответ 3

Вам не нужен линейный индекс, вы можете просто сравнить его лексикографически:

friend bool operator< (const Object &lhs, const Object &rhs) {
  if (lhs.color < rhs.color) return true;
  else if (lhs.color > rhs.color) return false;
  else return lhs.shape < rhs.shape;
}

Ответ 4

Это хороший вопрос, но вам действительно не нужно количество Color для их сравнения:

friend bool operator< (const Object &lhs, const Object &rhs) {
    if(lhs.color > rhs.color) {
        return false;
    }
    if(lhs.color < rhs.color) { 
        return true;
    }
    return lhs.shape < rhs.shape;
}

Ответ 5

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

friend bool operator< (const Object &lhs, const Object &rhs) 
{
   return ( (lhs.color < rhs.color) 
           || ( (lhs.color == rhs.color ) && ( lhs.shape < rhs.color) ) )
}

EDIT: на самом деле вы также можете использовать верхнюю границу для количества объектов, поведение будет одинаковым:

friend bool operator< (const Object &lhs, const Object &rhs) {
  return 10000*lhs.color+lhs.shape < 10000*rhs.color+rhs.shape;
}

но это вводит "магическое число" (так что не такая хорошая идея).

Ответ 6

Вам нужно сравнить shape, если color одинаково для обоих.

Используя тройной, вы можете сделать так, чтобы он выглядел хорошо:

friend bool operator< (const Object &lhs, const Object &rhs) {
     return lhs.color == rhs.color ? (lhs.shape < rhs.shape)
                                   : (lhs.color < rhs.color);
}