I made an iterable generator for enums that conform with the following rules:
The class looks like this:
template <typename EnumType, EnumType LENGTH>
class EnumArrayNonStatic
{
public:
  using ValueType = typename std::underlying_type<EnumType>::type;
  //! Initialize values via private constructor
  constexpr EnumArrayNonStatic() : EnumArrayNonStatic(std::make_integer_sequence<ValueType, (ValueType)LENGTH>{}) {}
  //! All values generated via std::integer_sequence
  EnumType values[(int)LENGTH];
private:
  //! Private constructor that populates values
  template <int... Indices>
  constexpr EnumArrayNonStatic(std::integer_sequence<int, Indices...>) : values{(static_cast<EnumType>(Indices))...} {}
};
Usage:
enum class TestEnum
{
  A,
  B,
  C,
  D,
  LENGTH
};
int main()
{
  for (const TestEnum val : EnumArrayNonStatic<TestEnum, TestEnum::LENGTH>().values)
  {
    std::cout << (int)val << "\n";
  }
  return 0;
}
However, I would instead like to be able to use EnumArray<TestEnum, TestEnum::LENGTH>::values and have the values generated via template during compilation. I wrote this:
template <typename EnumType, EnumType LENGTH>
class EnumArray
{
private:
  using ValueType = typename std::underlying_type<EnumType>::type;
  //! Static generator of value array (returns EnumType[])
  template <ValueType... Indices>
  static constexpr auto GenerateArray(std::integer_sequence<ValueType, Indices...>) { return {(static_cast<EnumType>(Indices))...}; }
public:
  //! Static array of values of an enum
  static constexpr EnumType values[static_cast<ValueType>(LENGTH)] = GenerateArray(std::make_integer_sequence<ValueType, static_cast<ValueType>(LENGTH) >{});
};
I've been messing around with the code for a while but I always keep getting errors. The version above prints:
1>enumiteratortest.cpp(22): error C3108: cannot deduce a type as an initializer list is not an expression
1>enumiteratortest.cpp(25): note: see reference to function template instantiation 'auto EnumArray<TestEnum,TestEnum::LENGTH>::GenerateArray<0,1,2,3>(std::integer_sequence<int,0,1,2,3>)' being compiled
1>enumiteratortest.cpp(52): note: see reference to class template instantiation 'EnumArray<TestEnum,TestEnum::LENGTH>' being compiled
1>enumiteratortest.cpp(22): error C2440: 'return': cannot convert from 'initializer list' to 'auto'
1>enumiteratortest.cpp(22): note: There is no context in which this conversion is possible
1>enumiteratortest.cpp(25): error C2440: 'initializing': cannot convert from 'void' to 'const EnumType [4]'
1>        with
1>        [
1>            EnumType=TestEnum
1>        ]
1>enumiteratortest.cpp(25): note: There are no conversions to array types, although there are conversions to references or pointers to arrays
Surely there must be a way to initialize the array statically. Is the GenerateArray even necessary? Isn't there a way to do this?
int myArray[] = std::integer_sequence<ValueType, Indices...>{Indices...}
Or something along the lines?
You cannot initialize a language array with an initializer_list. And, you cannot change the return type of that function to an array - functions cannot return arrays.
Just change everything to std::array:
template <ValueType... Indices>
static constexpr auto GenerateArray(std::integer_sequence<ValueType, Indices...>)
    -> std::array<EnumType, sizeof...(Indices)>
{
    return {(static_cast<EnumType>(Indices))...};
}
static constexpr std::array<EnumType,  static_cast<ValueType>(LENGTH)> values
      = GenerateArray(std::make_integer_sequence<ValueType, static_cast<ValueType>(LENGTH)>{});
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With