c++enumsguideline-support-library

enum value as index of gsl::multi_span


I'd like to use an enum to access elements in a gsl::multi_span. It works fine with int, so I thought it'd work with enum values as the underlying type is int too:

#include <gsl/multi_span>
#include <iostream>

int main(int argc, char *argv[]) {
  const auto NUMBER_OF_PARAMS{2};
  if (argc != NUMBER_OF_PARAMS) {
    return -1;
  }

  enum param_index { PROG_NAME = 0, PARAM1 };
  const auto args = gsl::multi_span<char *>(argv, argc);

  // compiles
  std::cout << "Program name: " << args[0] << '\n';
  std::cout << "Parameter: " << args[1] << '\n';

  // does not compile
  std::cout << "Program name: " << args[param_index::PROG_NAME] << '\n';
  std::cout << "Parameter: " << args[param_index::PARAM1] << '\n';
}

GCC version 7 tells me:

src/so.cpp:16:40: error: no match for ‘operator[]’ (operand types are ‘const gsl::multi_span<char*>’ and ‘main(int, char**)::param_index’)
   std::cout << "Program name: " << args[param_index::PROG_NAME] << '\n';
                                        ^
In file included from src/so.cpp:1:0:
./GSL/include/gsl/multi_span:1494:25: note: candidate: constexpr gsl::multi_span<ValueType, FirstDimension, RestDimensions>::reference gsl::multi_span<ValueType, FirstDimension, RestDimensions>::operator[](const index_type&) const [with ValueType = char*; long int FirstDimension = -1; long int ...RestDimensions = {}; gsl::multi_span<ValueType, FirstDimension, RestDimensions>::reference = char*&; gsl::multi_span<ValueType, FirstDimension, RestDimensions>::index_type = gsl::index<1>]
     constexpr reference operator[](const index_type& idx) const GSL_NOEXCEPT
                         ^~~~~~~~
./GSL/include/gsl/multi_span:1494:25: note:   no known conversion for argument 1 from ‘main(int, char**)::param_index’ to ‘const index_type& {aka const gsl::index<1>&}’
./GSL/include/gsl/multi_span:1500:19: note: candidate: template<bool Enabled, class Ret> constexpr Ret gsl::multi_span<ValueType, FirstDimension, RestDimensions>::operator[](gsl::multi_span<ValueType, FirstDimension, RestDimensions>::size_type) const [with bool Enabled = Enabled; Ret = Ret; ValueType = char*; long int FirstDimension = -1; long int ...RestDimensions = {}]
     constexpr Ret operator[](size_type idx) const GSL_NOEXCEPT
                   ^~~~~~~~
./GSL/include/gsl/multi_span:1500:19: note:   template argument deduction/substitution failed:

Could someone explain me why the template argument deduction fails in this case? Is there a workaround?


Solution

  • The reason is fairly simple. gsl::index is a type that can only be copy-initialized with a value if its type satisfies details::are_integral, or if the type satisfies std::is_integral. This is true for int, but not for enums. You'll need to use static_cast, like:

    static_cast<int>(param_index::PROG_NAME)