如何在没有显式转换的情况下使用 C++ 枚举类枚举器作为 std::array 索引

lts*_*tar 6 c++ arrays indexing enums c++11

std:array当我想引用特定索引时,我想使用 C++ 枚举类作为索引而不调用显式转换。

我还使用 atypedef作为固定大小的std::array.

typedef std::array<int, 3> MyType;
enum class MyEnum {
  ENUMERATOR0 = 0,
  ENUMERATOR1 = 1,
  ENUMERATOR2 = 2,
};
Run Code Online (Sandbox Code Playgroud)

所以不要使用:

MyType my_type = {0};
my_type[static_cast<int>(MyEnum::ENUMERATOR0)] = 42;
Run Code Online (Sandbox Code Playgroud)

我想使用:

my_type[MyEnum::ENUMERATOR0] = 42;
Run Code Online (Sandbox Code Playgroud)

因此,我假设需要重载我的MyType( std::array) 类型的下标运算符。但是,我不知道如何在我的情况下重载下标运算符。为简单起见,我想避免使用类而不是 typedef。我怎样才能做到这一点?

jor*_*rdi 5

我为此找到了一个很好的解决方案。您既可以使用枚举类作为数组中的索引,也可以通过继承 std::array 并覆盖其 operator[] 方法来获得确保类型安全(即防止使用错误的枚举类型作为索引)的额外好处。

这是一个例子。

您可以像这样定义 enum_array :

#include <array>

// this is a new kind of array which accepts and requires its indices to be enums
template<typename E, class T, std::size_t N>
class enum_array : public std::array<T, N> {
public:
    T & operator[] (E e) {
        return std::array<T, N>::operator[]((std::size_t)e);
    }

    const T & operator[] (E e) const {
        return std::array<T, N>::operator[]((std::size_t)e);
    }
};
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

int main() {
    enum class Fruit : unsigned int {
        Apple,
        Kiwi
    };

    enum class Vegetable : unsigned int {
        Carrot,
        Potato
    };

    // Old way:
    std::array<int, 3> old_fruits;
    std::array<int, 3> old_veggies;

    old_fruits[(int)Fruit::Apple] = 3;          // compiles but "ugly"
    old_veggies[(int)Vegetable::Potato] = 7;    // compiles but "ugly"

    old_fruits[(int)Vegetable::Potato] = 3;     // compiles but shouldn't compile!
    old_fruits[2] = 6;                          // compiles but may or may not be desirable

    // New way:
    enum_array<Fruit, int, 3> fruits;
    enum_array<Vegetable, int, 3> veggies;

    fruits[Fruit::Apple] = 3;
    veggies[Vegetable::Potato] = 7;

    // fruits[Vegetable::Potato] = 3;   // doesn't compile :)
    // fruits[2] = 6;                   // doesn't compile
    // fruits[(int)Fruit::Apple] = 3;   // doesn't compile
} 
Run Code Online (Sandbox Code Playgroud)

  • 标准容器通常不被设计为派生(即没有虚拟析构函数等)。在这种情况下,封装通常是比继承更好的选择。 (2认同)

Yak*_*ont 1

您不能覆盖[]不属于您的类型。

请参阅http://en.cppreference.com/w/cpp/language/operators——不能是非operaror[]成员重载。

你可以这样做:

template<class E, class T, std::size_t N=E::count>
struct enum_array: std::array<T, N>{
  using base= std::array<T, N>;
  constexpr enum_array():base{}{}
  template<class A0, class...Args,
    std::enable_if_t<!std::is_same<T, std::decay_t<A0>>{}, bool>=true
  >
  constexpr enum_array(A0&& a0, Args&&...args):base{{std::forward<A0>(a0), std::forward<Args>(args)...}}{}
  // using base::operator[]; // -- if you want to expose [size_t] as well
  constexpr T& operator[](E const& e){ return base::operator[](static_cast<std::size_t>(e)); }
  constexpr T const& operator[](E const& e)const{ return base::operator[](static_cast<std::size_t>(e)); }
};
Run Code Online (Sandbox Code Playgroud)

这是接近的。代替

MyType x={{1,2,3}};
Run Code Online (Sandbox Code Playgroud)

enum_array<MyEnum, int> x={1,2,3};
Run Code Online (Sandbox Code Playgroud)

并添加countMyEnum.