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

"эмуляция класса enum" или твердая альтернатива для MSVC 10.0

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

enum class my_enum
{
    value1,
    value2
};

Это позволяет использовать следующее:

my_enum e = my_enum::value1;

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

4b9b3361

Ответ 1

Я только что обнаружил проблему с хорошим взломом Джеймса (который я использовал до сих пор) и исправление проблемы. Я обнаружил проблему, когда попытался определить оператор потока для 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);

Примечания:

  • Если иное не указано базой enum, базовый тип перечисления с областью - int.
  • Разрешены явные преобразования в базовый тип интеграла и из него. Но неявных преобразований нет. Сделайте все возможное.
  • Этот хак - скорее лаваш, чем Джеймс, из-за необходимости перечислить значения дважды. Я надеюсь, что компиляторы без поддержки enum enum быстро исчезнут!

Ответ 2

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

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

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

struct my_enum {
    enum type { 
        value1, 
        value2 
    };

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

    operator type() const { return value_; }

private:

    type value_;
};

Ответ 3

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

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

В приложении появился следующий код, построенный на решении Howard Hinnant:

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.");
    }
}

Не особенно замечательно, но, насколько я понимаю, я думаю...