эмуляция enum class или твердая альтернатива для MSVC 10.0 - PullRequest
12 голосов
/ 12 февраля 2011

Я ищу хакерское решение следующей проблемы: GCC 4.4+ принимает следующий код c ++ 0x:

enum class my_enum
{
    value1,
    value2
};

, который позволяет использовать его следующим образом:

my_enum e = my_enum::value1;

со всеми прибамбасами.Я хотел бы сделать этот код совместимым с MSVC 2010, чтобы синтаксис использования не менялся.Я уже размышлял над этим до здесь , и принятый ответ работает, но необходимость двух разных имен для перечисления и значения перечисления убивает совместимость двух подходов.Это делает невозможным замену кода C ++ 0x как есть.Мне было интересно, могут ли обойти некоторые хитрости #undef и #define, что позволит мне использовать enum class -подобный синтаксис (возможно, без строгой безопасности типов и т. Д.), Но по крайней мере тот же синтаксис,Спасибо!

Ответы [ 3 ]

21 голосов
/ 16 мая 2011

Я только что обнаружил проблему с хорошим взломом Джеймса (которым я раньше пользовался) и исправление этой проблемы. Я обнаружил проблему, когда попытался определить оператор потока для my_enum.

#include <iostream>

struct my_enum {
    enum type { 
        value1, 
        value2 
    };

    my_enum(type v) : value_(v) { }

    operator type() const { return value_; }

private:

    type value_;
};

std::ostream&
operator<<(std::ostream& os, my_enum v)
{
    return os << "streaming my_enum";
}

int main()
{
    std::cout << my_enum::value1 << '\n';
}

Вывод:

0

Проблема в my_enum::value1 имеет тип, отличный от my_enum. Вот взломать взлом Джеймса, который я придумал.

struct my_enum
{
    static const my_enum value1;
    static const my_enum value2;

    explicit my_enum(int v) : value_(v) { }

    // explicit // if you have it!
       operator int() const { return value_; }

private:

    int value_;
};

my_enum const my_enum::value1(0);
my_enum const my_enum::value2(1);

Примечания:

  1. Если иное не указано enum-base , базовый тип перечисления с областью действия int.
  2. Разрешены явные преобразования в базовый интегральный тип и из него. Но неявные преобразования не являются. Делай все возможное.
  3. Этот хак больше пита, чем Джеймс, из-за необходимости дважды перечислять значения. Я надеюсь, что компиляторы без поддержки перечисления enoped быстро исчезнут!
5 голосов
/ 12 февраля 2011

Не используйте это решение.Посмотрите принятый ответ Говарда для лучшего решения.Я оставляю этот пост здесь, потому что ответ Говарда относится к нему.

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

Тем не менее, как обходной путь взлома, вы можете заключить enum в struct и использовать пару неявныхконверсии:

struct my_enum {
    enum type { 
        value1, 
        value2 
    };

    my_enum(type v) : value_(v) { }

    operator type() const { return value_; }

private:

    type value_;
};
0 голосов
/ 07 ноября 2012

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

  1. Неявно преобразуемым в целочисленный тип
  2. Используется в операторе switch
  3. Используется в качестве нетипового параметра шаблона

In разработали следующий код, построенный по решению Говарда Хиннанта:

struct DataType
{
    struct integral {
        enum type { None, Single, Double, Int };
    };

    typedef typename integral::type integral_type;

    explicit DataType(integral_type v) : val(v) {}
    integral_type integral_value() const { return val; }

    bool operator==(const DataType& s) const { return val == s.val; }
    bool operator!=(const DataType& s) const { return val != s.val; }

    static const DataType None;
    static const DataType Single;
    static const DataType Double;
    static const DataType Int;

private:
    integral_type val;
};

В файле .cpp:

const DataType DataType::None   (DataType::integral::None);
const DataType DataType::Single (DataType::integral::Single);
const DataType DataType::Double (DataType::integral::Double);
const DataType DataType::Int    (DataType::integral::Int);

Как невведите параметр шаблона:

template <DataType::integral_type>
struct DataTypeTraits;

template <>
struct DataTypeTraits<DataType::integral::Single>
{
    enum { size = 4 };
};

В переключателе:

size_t get_size(DataType type)
{
    switch (type.integral_value()) {
        case DataType::integral::Single:  return DataTypeTraits<DataType::integral::Single>::size;
        case DataType::integral::Double:  return DataTypeTraits<DataType::integral::Double>::size;
        case DataType::integral::Int:     return DataTypeTraits<DataType::integral::Int>::size;
        default:                          throw  std::logic_error("Unknown data type.");
    }
}

Не особенно здорово, но это так же хорошо, как и получается, я думаю ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...