Создание составного типа из двух классов 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};
Ответы
Ответ 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);
}