“enum class” emulation or solid alternative for MSVC 10.0

后端 未结 3 566
无人共我
无人共我 2020-12-05 11:30

I\'m looking for a hacky kind of solution to the following problem: GCC 4.4+ accepts the following c++0x code:

enum class my_enum
{
    value1,
    value2
};         


        
相关标签:
3条回答
  • 2020-12-05 12:13

    I just discovered a problem with James' good hack (which I have heretofore been using), and a fix to the problem. I discovered the problem when I tried to define a stream operator for 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';
    }
    

    The output is:

    0
    

    The problem is my_enum::value1 has different type than my_enum. Here's a hack to James' hack that I came up with.

    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);
    

    Notes:

    1. Unless otherwise specified by an enum-base, the underlying type of a scoped enumeration is int.
    2. Explicit conversions to and from the underlying integral type are allowed. But implicit conversions are not. Do your best.
    3. This hack is more of a pita than James' because of the need to enumerate the values twice. I'm hoping compilers without scoped enum support rapidly become extinct!
    0 讨论(0)
  • 2020-12-05 12:20

    Do not use this solution. See the accepted answer by Howard for a better solution. I'm leaving this post here because Howard's answer refers to it.

    If you need to be able to compile your code with a compiler that doesn't yet support a new, not yet standard or not yet widely implemented language feature, it's best to avoid using that language feature in your code.

    That said, as a hack workaround, you can wrap the enum in a struct and use a pair of implicit conversions:

    struct my_enum {
        enum type { 
            value1, 
            value2 
        };
    
        my_enum(type v) : value_(v) { }
    
        operator type() const { return value_; }
    
    private:
    
        type value_;
    };
    
    0 讨论(0)
  • 2020-12-05 12:26

    I have been fighting for a whole day to find a truly optimal solution, but there doesn't seem to be one. I need my enum that is

    1. Not implicitly convertible to an integral type
    2. Usable in a switch statement
    3. Usable as non-type template parameter

    In have come up with the following code, built upon Howard Hinnant's solution:

    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;
    };
    

    In the .cpp file:

    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);
    

    As non-type template parameter:

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

    In a switch:

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

    Not particularly great, but that's as good as it gets, I guess...

    0 讨论(0)
提交回复
热议问题