-->

运营商枚举类的实现(Implementation of operators for enum cla

2019-07-21 18:48发布

继有问题的讨论增量方向和“枚举类”的递减 ,我想请教一下可能的实现算术运算符的enum class类型。

从原来的问题例如:

enum class Colors { Black, Blue, White, END_OF_LIST };

// Special behavior for ++Colors
Colors& operator++( Colors &c ) {
  c = static_cast<Colors>( static_cast<int>(c) + 1 );
  if ( c == Colors::END_OF_LIST )
    c = Colors::Black;
  return c;
}

有没有办法实现算术运算符,而不铸造与已经定义运营商型的方法吗? 我想不出任何,但铸造困扰我。 类型转换通常是一些错误指示,并必须有对他们的使用一个很好的理由。 我希望的语言,以便实现操作者是可以实现不强制特定类型。

更新2018年12月 :一朝向C ++ 17似乎通过允许枚举类变量和底层类型之间的转换至少部分地解决此的论文: http://www.open-std.org/jtc1/sc22/wg21/文档/文件/ 2016 / p0138r2.pdf

Answer 1:

无铸解决方案是使用开关。 但是,您可以使用模板生成伪开关。 其原理是递归过程中使用的模板列表(或参数组)枚举的所有值。 因此,这里有3种方法,我发现。

测试枚举:

enum class Fruit
{
    apple,
    banana,
    orange,
    pineapple,
    lemon
};

香草开关(住在这里) :

/// Non-scalable way
Fruit& operator++(Fruit& f)
{
    switch(f)
    {
        case Fruit::apple: return f = Fruit::banana;
        case Fruit::banana: return f = Fruit::orange;
        case Fruit::orange: return f = Fruit::pineapple;
        case Fruit::pineapple: return f = Fruit::lemon;
        case Fruit::lemon: return f = Fruit::apple;
    }
}

在C ++ 03-ISH法(住在这里) :

template<typename E, E v>
struct EnumValue
{
    static const E value = v;
};

template<typename h, typename t>
struct StaticList
{
    typedef h head;
    typedef t tail;
};

template<typename list, typename first>
struct CyclicHead
{
    typedef typename list::head item;
};

template<typename first>
struct CyclicHead<void,first>
{
    typedef first item;
};

template<typename E, typename list, typename first = typename list::head>
struct Advance
{
    typedef typename list::head lh;
    typedef typename list::tail lt;
    typedef typename CyclicHead<lt, first>::item next;

    static void advance(E& value)
    {
        if(value == lh::value)
            value = next::value;
        else
            Advance<E, typename list::tail, first>::advance(value);
    }
};

template<typename E, typename f>
struct Advance<E,void,f>
{
    static void advance(E& value)
    {
    }
};

/// Scalable way, C++03-ish
typedef StaticList<EnumValue<Fruit,Fruit::apple>,
        StaticList<EnumValue<Fruit,Fruit::banana>,
        StaticList<EnumValue<Fruit,Fruit::orange>,
        StaticList<EnumValue<Fruit,Fruit::pineapple>,
        StaticList<EnumValue<Fruit,Fruit::lemon>,
        void
> > > > > Fruit_values;

Fruit& operator++(Fruit& f)
{
    Advance<Fruit, Fruit_values>::advance(f);
    return f;
}

在C ++ 11-ISH法(住在这里) :

template<typename E, E first, E head>
void advanceEnum(E& v)
{
    if(v == head)
        v = first;
}

template<typename E, E first, E head, E next, E... tail>
void advanceEnum(E& v)
{
    if(v == head)
        v = next;
    else
        advanceEnum<E,first,next,tail...>(v);
}

template<typename E, E first, E... values>
struct EnumValues
{
    static void advance(E& v)
    {
        advanceEnum<E, first, first, values...>(v);
    }
};

/// Scalable way, C++11-ish
typedef EnumValues<Fruit,
        Fruit::apple,
        Fruit::banana,
        Fruit::orange,
        Fruit::pineapple,
        Fruit::lemon
> Fruit_values11;

Fruit& operator++(Fruit& f)
{
    Fruit_values11::advance(f);
    return f;
}

(C ++ 11上下的旧版本)

您可以通过添加一些预处理去除需要重复的值列表扩展。



Answer 2:

用C各运营商++枚举上可以在不转换成一基本类型被写入,但其结果将是可笑冗长。

举个例子:

size_t index( Colors c ) {
  switch(c) {
    case Colors::Black: return 0;
    case Colors::Blue: return 1;
    case Colors::White: return 2;
  }
}
Color indexd_color( size_t n ) {
  switch(n%3) {
    case 0: return Colors::Black;
    case 1: return Colors::Blue;
    case 2: return Colors::White;
  }
}
Colors increment( Colors c, size_t n = 1 ) {
  return indexed_color( index(c) + n );
}
Colors decrement( Colors c, size_t n = 1 ) {
  return indexed_color( index(c)+3 - (n%3) );
}
Colors& operator++( Colors& c ) {
  c = increment(c)
  return c;
}
Colors operator++( Colors& c, bool ) {
  Colors retval = c;
  c = increment(c)
  return retval;
}

和智能编译器将能够把它们转变成能够直接上基整体式操作。

但铸在你的界面基本整数类型enum class是不是一件坏事。 和运营商对您的接口的一部分enum class

如果你不喜欢通过循环size_t并认为这是一个假的转换,你可以这样写:

Colors increment( Colors c ) {
  switch(c) {
    case Colors::Black: return Colors::Blue;
    case Colors::Blue: return Colors::White;
    case Colors::White: return Colors::Black;
  }
}

同样地,对于递减,并执行增量逐n作为重复的循环increment



Answer 3:

enum class Colors { Black, Blue, White };

Colors operator++(Colors& color)
{
    color = (color == Colors::White) ? Colors::Black : Colors(int(color) + 1);
    return color;
}

检查C ++壳牌



文章来源: Implementation of operators for enum class