1

Let's say I have an alias for vector:

typedef std::vector<double> PlanetData;

And I want it's fields to be accessible via some keys:

double x = planet_data[PlanetDataKeys::PosX]; //planet_data is of type PlanetData

How can I achieve it?

I can define an enum inside a namespace:

namespace PlanetDataKeys {
  enum {
    PosX = 0,
    PosY = 1
  };
}

But enum class is safer:

enum class PlanetDataKeys {
  PosX = 0,
  PosY = 1
};

However, as implicit casting of enum class to int type is disabled, this would require to write:

double x =  planet_data[static_cast<int>(PlanetDataKeys::PosX)];

which is a bit awkward .

Which approach is better in this case and why?

EDIT Some explanation for aliasing vector:

In real code, PlanetData have ~7 fields, maybe even more if I decide to expand it. And I'm creating an instance of it while parsing a string of form data_string = "date: 2903248.12343, position=[124543254.1343214,123213.12341,63456.1234], velocity=[...". That's why I wanted it to be a vector: to use something like planet_data.push_back(ParseNextDouble(data_string));

  • 1
    The only thing that's safer about `enum class` is the lack of implicit conversion from enum to the underlying type, which is the issue you're expeciencing. Thus I'd just use a normal `enum` in a namespace. – HolyBlackCat Aug 02 '17 at 10:24
  • @HolyBlackCat That's the only thing? Isn't preventing redefinition of keys another one? – Przemysław Czechowski Aug 02 '17 at 10:26
  • are you really having a `std::vector` that's always going to be of size 2? – bolov Aug 02 '17 at 10:27
  • @PrzemysławCzechowski Can you elaborate? If you're talking about enumerators with duplicate values, they [seem to be allowed](http://coliru.stacked-crooked.com/a/ba9e8daf5ee839f3). – HolyBlackCat Aug 02 '17 at 10:28
  • @bolov No, actually it's going to be of size ~7, maybe more. I wanted to use simple `push_back` while parsing data to put inside – Przemysław Czechowski Aug 02 '17 at 10:29
  • @PrzemysławCzechowski (about new keys) not really: if you want you can do: `PlanetDataKeys k = static_cast(42);` – bolov Aug 02 '17 at 10:31
  • If you know vector size in advance with strict meaning of every item in it then how about using class instead? – user7860670 Aug 02 '17 at 10:39
  • @HolyBlackCat I thought that primary reason to use `enum class` it that you can have same key name in two enums . But enum in namespace also allows that - namespaces just have to be different. So, you're right. There are no benefits of using `enum class` here. I got it wrong. – Przemysław Czechowski Aug 02 '17 at 10:41
  • I would use `struct PlanetData { double x; double y; };` instead of `std::vector`. –  Aug 02 '17 at 11:22

2 Answers2

2

Please don't expect too much functionality from a humble vector.

Vector is not designed to access it's data with keys other than indices. Despite your examples are syntactically and semantically correct, they look like a misuse of std::vector and enum classes. Each tool has it's purpose, and vector seems to be not the best one for your task.

Enum classes were introduced to improve type safety. With them, you'll never mix up PlanetDataKeys, SatelliteEphemeris and KeplerianOrbitElements. But in your case you finally cast any of them to int, loosing all the conquest of type-safe enums.

As to me, it would be better to define a PlanetData class with a subscript operator which accepts PlanetDataKeys as it's argument.

If you want to stick with vectors, I'd choose the first variant (with namespaces). It's much easier to read and write, and I'm convinced that it's not even a little safer than enum classes used this way.

Sergey
  • 7,985
  • 4
  • 48
  • 80
0

What about just defining scoped constants of the appropriate type, like so:

namespace PlanetDataKeys {
  const size_t PosX = 0;
  const size_t PosY = 1;
}
virgesmith
  • 762
  • 1
  • 7
  • 18