Additional answer from old_mountain answer:
In some cases, you can remember to add new values ββto your list using fixed arrays. The main problem is that the initializer takes fewer arguments than indicated, but you can get around this:
template<typename T, typename...Args> struct first_type { using type = T; }; template<typename... Args> std::array<typename first_type<Args...>::type, sizeof...(Args)> make_array(Args&&... refs) { return std::array<typename first_type<Args...>::type, sizeof...(Args)>{ { std::forward<Args>(refs)... } }; }
I found make_array inspired in this question, but changed it: How to emulate C array initialization and int arr [] = {e1, e2, e3, ...} "behavior with std :: array?
What he does is use the first argument to determine the type of std::array and the number of arguments to get the actual size. Thus, the return type is std::array<firstType, numArgs> .
Now declare your lists as follows:
const std::array<Suit, (size_t)Suit::enum_count> SuitValues = make_array(Suit::clubs, Suit::diamonds, Suit::hearts, Suit::spades); const std::array<Rank, (size_t)Rank::enum_count> RankValues = make_array(Rank::one, Rank::two, Rank::three, Rank::four, Rank::five, Rank::six, Rank::seven, Rank::eight, Rank::nine, Rank::ten, Rank::jack, Rank::queen, Rank::king, Rank::ace);
When you add a value to the array, your enum_count or any other value that you use as a separator will change, and therefore the assignment from make_array will fail, as the sizes of both std::array will be different (which leads to different types).
Example:
If you just add a new Suit , say hexa
enum class Suit : int { clubs, diamonds, hearts, spades, hexa, enum_count };
Compiler Crash:
cannot convert from 'std::array<T,0x04>' to 'const std::array<Suit,0x05>'
I have to admit that I am not 100% satisfied with this solution, as declaring an array requires a pretty ugly tide of size_t .