Какие типы типов Enum в C++ вы используете?
Общеизвестно, что встроенные перечисления 9X_design-patterns в C++ небезопасны. Мне было интересно, какие 9X_enum классы, реализующие типизированные перечисления, используются 9X_enumerations там ... Я сам использую следующий «велосипед», но 9X_design-pattern он несколько многословен и ограничен:
typesafeenum.h:
struct TypesafeEnum
{
// Construction:
public:
TypesafeEnum(): id (next_id++), name("") {}
TypesafeEnum(const std::string& n): id(next_id++), name(n) {}
// Operations:
public:
bool operator == (const TypesafeEnum& right) const;
bool operator != (const TypesafeEnum& right) const;
bool operator < (const TypesafeEnum& right) const;
std::string to_string() const { return name; }
// Implementation:
private:
static int next_id;
int id;
std::string name;
};
typesafeenum.cpp:
int TypesafeEnum::next_id = 1;
bool TypesafeEnum::operator== (const TypesafeEnum& right) const
{ return id == right.id; }
bool TypesafeEnum::operator!= (const TypesafeEnum& right) const
{ return !operator== (right); }
bool TypesafeEnum::operator< (const TypesafeEnum& right) const
{ return id < right.id; }
Использование:
class Dialog
{
...
struct Result: public TypesafeEnum
{
static const Result CANCEL("Cancel");
static const Result OK("Ok");
};
Result doModal();
...
};
const Dialog::Result Dialog::Result::OK;
const Dialog::Result Dialog::Result::CANCEL;
Дополнение: Думаю, мне 9X_enum следовало более конкретно рассказать о требованиях. Попробую 9X_gof их резюмировать:
Приоритет 1: установка недопустимого 9X_gof значения для переменной enum должна быть 9X_enum невозможной (ошибка времени компиляции) без 9X_c++03 исключений.
Приоритет 2: преобразование значения 9X_patterns перечисления в / из int должно быть возможным 9X_gang-of-four с помощью одного явного вызова функции / метода.
Приоритет 9X_patterns 3: максимально компактное, элегантное и 9X_design-patterns удобное объявление и использование
Приоритет 9X_enumerations 4: преобразование значений перечисления 9X_patterns в строки и обратно.
Приоритет 5: (Приятно 9X_design-pattern иметь) возможность перебирать значения перечисления.
Ответ #1
Ответ на вопрос: Какие типы типов Enum в C++ вы используете?
В настоящее время я играю с предложением 9X_enums Boost.Enum из Boost Vault (filename enum_rev4.6.zip
). Хотя он никогда 9X_enumerations официально не подавался на включение в Boost, его 9X_gang-of-four можно использовать как есть. (Документация 9X_enumeration отсутствует, но она компенсируется ясным 9X_type-safety исходным кодом и хорошими тестами.)
Boost.Enum 9X_c++03 позволяет вам объявить перечисление следующим 9X_enums образом:
BOOST_ENUM_VALUES(Level, const char*,
(Abort)("unrecoverable problem")
(Error)("recoverable problem")
(Alert)("unexpected behavior")
(Info) ("expected behavior")
(Trace)("normal flow of execution")
(Debug)("detailed object state listings")
)
И пусть он автоматически расширяется 9X_patterns до этого:
class Level : public boost::detail::enum_base
{
public:
enum domain
{
Abort,
Error,
Alert,
Info,
Trace,
Debug,
};
BOOST_STATIC_CONSTANT(index_type, size = 6);
Level() {}
Level(domain index) : boost::detail::enum_base(index) {}
typedef boost::optional optional;
static optional get_by_name(const char* str)
{
if(strcmp(str, "Abort") == 0) return optional(Abort);
if(strcmp(str, "Error") == 0) return optional(Error);
if(strcmp(str, "Alert") == 0) return optional(Alert);
if(strcmp(str, "Info") == 0) return optional(Info);
if(strcmp(str, "Trace") == 0) return optional(Trace);
if(strcmp(str, "Debug") == 0) return optional(Debug);
return optional();
}
private:
friend class boost::detail::enum_base;
static const char* names(domain index)
{
switch(index)
{
case Abort: return "Abort";
case Error: return "Error";
case Alert: return "Alert";
case Info: return "Info";
case Trace: return "Trace";
case Debug: return "Debug";
default: return NULL;
}
}
typedef boost::optional optional_value;
static optional_value values(domain index)
{
switch(index)
{
case Abort: return optional_value("unrecoverable problem");
case Error: return optional_value("recoverable problem");
case Alert: return optional_value("unexpected behavior");
case Info: return optional_value("expected behavior");
case Trace: return optional_value("normal flow of execution");
case Debug: return optional_value("detailed object state listings");
default: return optional_value();
}
}
};
Он удовлетворяет всем пяти перечисленным 9X_c++03 вами приоритетам.
- зачем это нужно для решения проблемы, которой не существует ?? !! * г ...
Ответ #2
Ответ на вопрос: Какие типы типов Enum в C++ вы используете?
Хороший компромиссный метод заключается 9X_pattern в следующем:
struct Flintstones {
enum E {
Fred,
Barney,
Wilma
};
};
Flintstones::E fred = Flintstones::Fred;
Flintstones::E barney = Flintstones::Barney;
Это небезопасно с точки зрения 9X_enumeration типов в том же смысле, что и ваша версия, но 9X_gang-of-four использование лучше, чем стандартные перечисления, и 9X_gang-of-four вы все равно можете воспользоваться преимуществами 9X_c++03 целочисленного преобразования, когда оно 9X_enumeration вам нужно.
- Продолжение вопроса о пространстве имен: для перечислений, которые находятся внутри класса или структуры, вы не можете использовать пространство имен. Если п ...
Ответ #3
Ответ на вопрос: Какие типы типов Enum в C++ вы используете?
Я использую C++0x typesafe enums. Я использую несколько вспомогательных 9X_gof шаблонов / макросов, которые обеспечивают 9X_design-pattern функциональность строки "от / до".
enum class Result { Ok, Cancel};
- @Roddy: значит, вы используете функцию, которую поддерживает только ** один ** к ...
Ответ #4
Ответ на вопрос: Какие типы типов Enum в C++ вы используете?
Я не знаю. Слишком много накладных расходов 9X_enum без особой пользы. Кроме того, очень удобным 9X_enum инструментом является возможность преобразовывать 9X_enums перечисления в разные типы данных для сериализации. Я 9X_design-patterns никогда не видел случая, когда перечисление 9X_gof «Типобезопасное» стоило бы накладных расходов 9X_design-patterns и сложности, когда C++ уже предлагает достаточно 9X_design-patterns хорошую реализацию.
- Типобезопасное перечисление может быть реализовано с использованием ...
Ответ #5
Ответ на вопрос: Какие типы типов Enum в C++ вы используете?
Я считаю, что вы придумываете проблему, а 9X_patterns затем подбираете для нее решение. Я не вижу 9X_gof необходимости создавать сложную структуру 9X_patterns для перечисления ценностей. Если вы преданы, чтобы 9X_type-safety ваши значения были только членами определенного 9X_enums набора, вы можете взломать вариант уникального 9X_enums типа данных набора.
Ответ #6
Ответ на вопрос: Какие типы типов Enum в C++ вы используете?
Я лично использую адаптированную версию 9X_c++03 typesafe enum idiom. Он не обеспечивает всех пяти «требований», которые 9X_enums вы указали в своей редакции, но я все равно 9X_pattern категорически не согласен с некоторыми из 9X_gang-of-four них. Например, я не понимаю, как Prio # 4 9X_pattern (преобразование значений в строки) имеет 9X_design-pattern какое-либо отношение к безопасности типов. В 9X_patterns большинстве случаев строковое представление 9X_enum отдельных значений в любом случае должно 9X_enumerations быть отделено от определения типа (подумайте 9X_patterns о i18n по простой причине). Prio # 5 (итерация, необязательный) - одна 9X_enumeration из самых приятных вещей, которые я хотел 9X_enumerations бы видеть естественным в перечислениях, поэтому мне 9X_c++03 было грустно, что в вашем запросе это выглядит 9X_type-safety как "необязательное", но кажется, что 9X_design-patterns это лучше решать с помощью separate iteration system, такого как 9X_enumeration функции begin
/ end
или enum_iterator, что позволяет 9X_gang-of-four им без проблем работать с STL и C++ 11 foreach.
OTOH 9X_design-patterns эта простая идиома прекрасно обеспечивает 9X_design-patterns Prio # 3 Prio # 1 благодаря тому, что в 9X_design-pattern основном она только обертывает enum
с дополнительной 9X_enums информацией о типе. Не говоря уже о том, что 9X_gang-of-four это очень простое решение, которое по большей 9X_type-safety части не требует никаких внешних заголовков 9X_c++03 зависимостей, поэтому его довольно легко 9X_enumerations носить с собой. Он также имеет то преимущество, что 9X_enum перечисления имеют область видимости а-ля-C++ 11:
// This doesn't compile, and if it did it wouldn't work anyway
enum colors { salmon, .... };
enum fishes { salmon, .... };
// This, however, works seamlessly.
struct colors_def { enum type { salmon, .... }; };
struct fishes_def { enum type { salmon, .... }; };
typedef typesafe_enum colors;
typedef typesafe_enum fishes;
Единственная 9X_gof "дыра", которую предоставляет 9X_c++03 решение, состоит в том, что оно не учитывает 9X_patterns тот факт, что оно не препятствует прямому 9X_gang-of-four сравнению enum
разных типов (или enum
и int), потому 9X_enumeration что когда вы используете значения напрямую, вы 9X_pattern вызываете неявное преобразование в int
:
if (colors::salmon == fishes::salmon) { .../* Ooops! */... }
Но до 9X_enumeration сих пор я обнаружил, что такие проблемы 9X_c++03 можно решить, просто предлагая лучшее сравнение 9X_enums с компилятором - например, явно предоставляя 9X_design-pattern оператор, который сравнивает любые два разных 9X_gang-of-four типа enum
, а затем заставляя его терпеть неудачу:
// I'm using backports of C++11 utilities like static_assert and enable_if
template
typename enable_if< (is_enum::value && is_enum::value) && (false == is_same::value) , bool >
::type operator== (Enum1, Enum2) {
static_assert (false, "Comparing enumerations of different types!");
}
Хотя 9X_pattern пока кажется, что это не нарушает код, а 9X_gang-of-four явно решает конкретную проблему, не делая 9X_gang-of-four чего-то еще, я не уверен, что это то, что 9X_patterns нужно "" "do (я подозреваю, что 9X_design-pattern это будет мешать enum
уже принимать участие 9X_pattern в операторах преобразования, объявленных 9X_enumerations где-то в другом месте; я с радостью получу 9X_enum комментарий по этому поводу).
Сочетание этого 9X_enums с приведенной выше идиомой типизации дает 9X_patterns нечто, относительно близкое к C++ 11 enum class
по 9X_enum человечности (удобочитаемость и ремонтопригодность) без 9X_gof необходимости делать что-то слишком непонятное. И 9X_pattern я должен признать, что это было весело, я 9X_design-patterns никогда не думал на самом деле спросить у компилятора, имею 9X_pattern ли я дело с enum
s или нет ...
Ответ #7
Ответ на вопрос: Какие типы типов Enum в C++ вы используете?
Я думаю, что Java enum
будет хорошей моделью 9X_gof для подражания. По сути, форма Java будет 9X_type-safety выглядеть так:
public enum Result {
OK("OK"), CANCEL("Cancel");
private final String name;
Result(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Что интересно в подходе Java, так 9X_enumeration это то, что OK
и CANCEL
являются неизменяемыми одноэлементными 9X_gang-of-four экземплярами Result
(с методами, которые вы видите). Вы 9X_c++03 не можете создавать дополнительные экземпляры 9X_enum Result
. Поскольку они синглтоны, вы можете сравнивать 9X_type-safety их по указателю / ссылке --- очень удобно. :-)
ETA: в 9X_enumerations Java вместо того, чтобы создавать битовые 9X_patterns маски вручную, вместо этого вы используете 9X_enum EnumSet
для указания набора бит (он реализует интерфейс 9X_enums Set
и работает как наборы, но реализован с 9X_design-pattern использованием битовых масок). Намного более 9X_enum читабельно, чем рукописные манипуляции с 9X_design-patterns битовой маской!
Ответ #8
Ответ на вопрос: Какие типы типов Enum в C++ вы используете?
Я дал ответ на этот here по другой теме. Это 9X_type-safety другой стиль подхода, который позволяет 9X_enumeration использовать большую часть тех же функций, не 9X_design-patterns требуя изменения исходного определения перечисления 9X_enumeration (и, следовательно, разрешая использование 9X_type-safety в случаях, когда вы не определяете перечисление). Он 9X_gang-of-four также позволяет проверять диапазон во время 9X_type-safety выполнения.
Обратной стороной моего подхода 9X_design-patterns является то, что он не обеспечивает программного 9X_design-pattern обеспечения связи между перечислением и 9X_pattern вспомогательным классом, поэтому их нужно 9X_enumeration обновлять параллельно. У меня работает, но 9X_patterns YMMV.
-
10
-
10
-
9
-
6
-
3
-
3
-
4
-
2
-
4
-
1
-
31
-
10
-
8
-
5
-
6
-
5
-
8
-
2
-
2
-
4
-
5
-
2
-
7
-
2
-
4
-
3
-
2
-
7
-
12
-
10
-
7
-
6
-
9
-
12
-
6
-
3
-
2
-
2
-
3
-
3
-
3
-
5
-
4
-
2
-
6
-
14
-
13
-
33
-
8
-
14