'enum class as array index
I made an enum as:
enum class KeyPressSurfaces {
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
KEY_PRESS_SURFACE_TOTAL
};
and later on I attempt to define an array as I typed below, but I received the error, size of array 'KEY_PRESS_SURFACES' has non-integral type 'KeyPressSurfaces'
SDL_Surface*KEY_PRESS_SURFACES[KeyPressSurfaces::KEY_PRESS_SURFACE_TOTAL];
I understand the error fine, but I don't know where to move the KeyPressSurfaces to qualify the constant in the enum.
I also realize I could just use an enum and not an enum class, but I feel like this should work, and I want to learn how to do this.
Any response/advice?
Solution 1:[1]
Scoped enums (enum class) are not implicitly convertible to integers. You need to use a static_cast:
SDL_Surface*KEY_PRESS_SURFACES[static_cast<int>(KeyPressSurfaces::KEY_PRESS_SURFACE_TOTAL)];
Solution 2:[2]
You can convert your enum to int using template function and you will get more readable code:
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
enum class KeyPressSurfaces: int {
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
KEY_PRESS_SURFACE_TOTAL
};
template <typename E>
constexpr typename std::underlying_type<E>::type to_underlying(E e) {
return static_cast<typename std::underlying_type<E>::type>(e);
}
int main() {
KeyPressSurfaces val = KeyPressSurfaces::KEY_PRESS_SURFACE_UP;
int valInt = to_underlying(val);
std::cout << valInt << std::endl;
return 0;
}
I fount to_underlying function here
Solution 3:[3]
Remove the class keyword or cast explicitly to an integral type.
Solution 4:[4]
Building on the other responses, another alternative is a simple templated class that wraps a c-style array. With the EnumArray example below, any enum class with a kMaxValue can be used as the index.
In my opinion, the improved readability is worth the introduction of a template.
template <class IndexType, class ValueType>
class EnumArray {
public:
ValueType& operator[](IndexType i) {
return array_[static_cast<int>(i)];
}
const ValueType& operator[](IndexType i) const {
return array_[static_cast<int>(i)];
}
int size() const { return size_; }
private:
ValueType array_[static_cast<int>(IndexType::kMaxValue) + 1];
int size_ = static_cast<int>(IndexType::kMaxValue) + 1;
};
enum class KeyPressSurfaces {
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
KEY_PRESS_SURFACE_TOTAL,
kMaxValue = KEY_PRESS_SURFACE_TOTAL
};
int main() {
EnumArray<KeyPressSurfaces, int> array;
array[KeyPressSurfaces::KEY_PRESS_SURFACE_DEFAULT] = 5;
std::cout << array[KeyPressSurfaces::KEY_PRESS_SURFACE_DEFAULT] << std::endl;
return 0;
}
Solution 5:[5]
You can work on the array:
/** \brief It's either this or removing the "class" from "enum class" */
template <class T, std::size_t N>
struct EnumClassArray : std::array<T, N>
{
template <typename I>
T& operator[](const I& i) { return std::array<T, N>::operator[](static_cast<std::underlying_type<I>::type>(i)); }
template <typename I>
const T& operator[](const I& i) const { return std::array<T, N>::operator[](static_cast<std::underlying_type<I>::type>(i)); }
};
Solution 6:[6]
You can use a namespace and anonymous enum. So you can get rid of these ugly prefixes and use enum items as index.
namespace KeyPressSurfaces
{
enum
{
DEFAULT = 0,
UP,
DOWN,
LEFT,
RIGHT,
TOTAL
};
}
SDL_Surface* KEY_PRESS_SURFACES[KeyPressSurfaces::TOTAL];
Solution 7:[7]
In addition to the currently accepted answer, you could write a function to get a reference to the surface:
enum class KeyPressSurface
{
DEFAULT,
UP,
DOWN,
LEFT,
RIGHT,
TOTAL
};
// This is using static_cast like the accepted answer
std::array<SDL_Surface *, static_cast<int>(KeyPressSurface::TOTAL)> keyPressSurfaces;
// Function to get a reference to a surface
SDL_Surface *&getKeyPressSurface(KeyPressSurface surface)
{
return keyPressSurfaces[static_cast<int>(surface)];
}
Now you can cleanly get a surface using the enum class:
// assignment
getKeyPressSurface(KeyPressSurface::UP) = SDL_LoadBMP("lamp.bmp");
// or get a value
SDL_Surface *currentSurface = getKeyPressSurface(KeyPressSurface::RIGHT);
Solution 8:[8]
Use struct members instead of enum.
struct KeyPressSurfaces {
static constexpr int KEY_PRESS_SURFACE_DEFAULT = 0;
static constexpr int KEY_PRESS_SURFACE_UP= 1;
static constexpr int KEY_PRESS_SURFACE_DOWN = 2;
static constexpr int KEY_PRESS_SURFACE_LEFT = 3;
static constexpr int KEY_PRESS_SURFACE_RIGHT = 4;
static constexpr int KEY_PRESS_SURFACE_TOTAL = 5;
};
Alternatively, have them in a namespace with the same logic, where you can benefit from using namespace.
namespace KeyPressSurfaces {
constexpr int KEY_PRESS_SURFACE_DEFAULT = 0;
constexpr int KEY_PRESS_SURFACE_UP= 1;
constexpr int KEY_PRESS_SURFACE_DOWN = 2;
constexpr int KEY_PRESS_SURFACE_LEFT = 3;
constexpr int KEY_PRESS_SURFACE_RIGHT = 4;
constexpr int KEY_PRESS_SURFACE_TOTAL = 5;
}
SDL_Surface* KEY_PRESS_SURFACES[KeyPressSurfaces::KEY_PRESS_SURFACE_TOTAL];
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Simple |
| Solution 2 | Community |
| Solution 3 | knivil |
| Solution 4 | eric |
| Solution 5 | Stefan |
| Solution 6 | GeorgeMakarov |
| Solution 7 | Joe' |
| Solution 8 | Burak |
