Какие типы типов 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 иметь) возможность перебирать значения перечисления.

45
0
8
Общее количество ответов: 8

Ответ #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 вами приоритетам.

42
5

  • зачем это нужно для решения проблемы, которой не существует ?? !! * г ...

Ответ #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 вам нужно.

18
4

  • Продолжение вопроса о пространстве имен: для перечислений, которые находятся внутри класса или структуры, вы не можете использовать пространство имен. Если п ...

Ответ #3

Ответ на вопрос: Какие типы типов Enum в C++ вы используете?

Я использую C++0x typesafe enums. Я использую несколько вспомогательных 9X_gof шаблонов / макросов, которые обеспечивают 9X_design-pattern функциональность строки "от / до".

enum class Result { Ok, Cancel};

14
3

  • @Roddy: значит, вы используете функцию, которую поддерживает только ** один ** к ...

Ответ #4

Ответ на вопрос: Какие типы типов Enum в C++ вы используете?

Я не знаю. Слишком много накладных расходов 9X_enum без особой пользы. Кроме того, очень удобным 9X_enum инструментом является возможность преобразовывать 9X_enums перечисления в разные типы данных для сериализации. Я 9X_design-patterns никогда не видел случая, когда перечисление 9X_gof «Типобезопасное» стоило бы накладных расходов 9X_design-patterns и сложности, когда C++ уже предлагает достаточно 9X_design-patterns хорошую реализацию.

6
1

  • Типобезопасное перечисление может быть реализовано с использованием ...

Ответ #5

Ответ на вопрос: Какие типы типов Enum в C++ вы используете?

Я считаю, что вы придумываете проблему, а 9X_patterns затем подбираете для нее решение. Я не вижу 9X_gof необходимости создавать сложную структуру 9X_patterns для перечисления ценностей. Если вы преданы, чтобы 9X_type-safety ваши значения были только членами определенного 9X_enums набора, вы можете взломать вариант уникального 9X_enums типа данных набора.

2
0

Ответ #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 или нет ...

2
0

Ответ #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 битовой маской!

1
0

Ответ #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.

1
0