1

Is there a way to get the memory/speed benefit of fixed length (known at compile-time) arrays while still having the static error checking and readability provided by enum class when indexing an array?

I exactly want the behavior of the array, except I want to disallow users from indexing by integers. I'd prefer to force writing potentially_descriptive_name[kLogicalRisingEdge] over potentially_descriptive_name[0] as I work with physicists who prioritize new results over writing maintainable codebase since they only need to work on it for 5-7 years before never seeing it again.

I'm hoping to have the ability to quickly iterate over subsets of data an arbitrary number of times (in my field, the filtered subset is called a "cut" of the data), but I need to perform this preprocessing first and I thought it would be great for readability to have an enum for the cut, so I can have something like what's below:

  1. have a header defining the cuts
// data_cuts.h
namespace data_cuts {
enum TimeCut {kInTime, kOutOfTime, kOther, N_elems}; // or enum class : uint?
TimeCut GetTimeCut(const Datum& d);

enum EdgeCut {kRising, kFalling, N_elems}; // sim
EdgeCut GetEdgeCut(const Datum& d);
}
  1. filling the data like this in one part of the project
for (const auto& d : full_data)
  data_by_time_cut[GetTimeCut(d)].push_back(datum);
  // potentially a much less memory intensive way to do this, but that should be addressed elsewhere
  1. reading said data in another part of the project
using namespace data_cuts;
for (TimeCut cut : std::vector<TimeCut>{kInTime, kOutOfTime})
  histograms_by_time_cut[cut].FillN(data_by_time_cut[c]);

for (const auto& d : data_by_time_cut[kInTime])
  histograms_by_time_cut[kInTime].FillSpecial(d);

but I don't know how to choose the type for data_by_time_cut and histograms_by_time_cut


Options I can think of, (I think improving as it goes down)

  1. I could use std::map<CutType, T> and enum class CutType and indexing is only permissible with CutType and not numeric-int or another type of cut, but I have all of map's overhead.

  2. I could use std::vector and convert the strongly typed enum to underlying every time I access, but it feels ungainly and it doesn't have the static check for generic integer indexing.

  3. I could use std::array and convert the strongly typed enum to underlying again.

  4. I could [learn how to and] write a template that wraps std::array and overloads operator[](T t) to call to_underlying and then I'm doing the above but less verbose. However, this just seems so generic, is this already implemented in a "better way" in C++14?

This is my attempt at the last option I listed, uses the code found here to define to_underlying

#include <array>
#include <vector>

template <typename E>
constexpr auto to_underlying(E e) noexcept
{
    return static_cast<std::underlying_type_t<E>>(e);
}

template <typename T, typename U>
class EnumIndexedArray
{
 public:
  EnumIndexedArray(){}; // should I add the other constructors?

  U& operator[](const T& t) {return m_arr[to_underlying(t)]; };
  const U& operator[](const T& t) const {return m_arr[to_underlying(t)]; };

 private:
  std::array<T, to_underlying(T::N_elems)> m_arr;
};

namespace data_cuts {
enum class TimeCut : char {kInTime, kOutOfTime, kOther, N_elems};
enum class EdgeCut : char {kRising, kFalling, N_elems};
}

class Datum;
class Histogram;
using Data = std::vector<Datum>;

EnumIndexedArray<data_cuts::TimeCut, Data> data_by_time_cut;
EnumIndexedArray<data_cuts::TimeCut, Histogram> histograms_by_time_cut;

I wonder if I'm adding too much for this to be a general question, so I'll stop for now.

Orion Yeung
  • 141
  • 1
  • 5
  • I personally would return `const U&` for the `const` overload. otherwise I don't see much problem here. – apple apple Aug 17 '22 at 21:19
  • tbh I don't really understand what "static check for generic integer indexing" means, you can easily case any (supported) value to the enum, even the unnamed ones. – apple apple Aug 17 '22 at 21:21
  • I am trying to avoid allowing `data_cut_by_time[0]` while maintaining the benefit of using `array`. I'll make the R value edit. Further, we can cut the data so that it's boolean (so only need 0,1 index), but to do that we need some process that identifies it as one or the other and the data can actually be uncategorized and need another index. – Orion Yeung Aug 17 '22 at 21:24
  • For `to_underlying` I'd use unary `operator+` to convert to underlying. But that's just me. – Eljay Aug 17 '22 at 22:03

0 Answers0