-2

I have an enum class which has 4 different values. A, B, C and D.

I have no control over what the underlying type is.

I have a vector of enums and I want to order it so all A are first. Then all B, Then all C and finally all D.

I can do it with very long if statements. But I wonder if there is an easy idiomatic way to achieve this.

edit: You are misunderstanding what I want. I have an enum class like this:

enum class MyEnum { A = 3, B = 1, C = 4, D = 2};

I have a vector of this enum and I want to order so that A is before B before C before D.

std::sort doesn't help at all here.

2 Answers2

2

A more runtime-efficient approach that avoids the 'switch' approach, or table-driven comparisons is:

inline bool operator<(MyEnum left, MyEnum right) {
  return static_cast<std::underlying_type_t<MyEnum>>(left) < static_cast<std::underlying_type_t<MyEnum>>(right);
}

for use in context where the enum needs to be orderable or sortable (such as std::sort) via std::less.

If you wanted to, you could templatize this comparison so that it affected every enum (or perhaps every enum that had some identifying feature, to cut down on clutter). The "every enum" approach might look something like this:

template <typename T, typename N=std::enable_if_t<std::is_enum_v<T>>>
inline bool operator<(T left, T right) {
  return static_cast<std::underlying_type_t<T>>(left) < static_cast<std::underlying_type_t<T>>(right);
}

The above code will sort by each enumerator's assigned values. If you want a different sort order, you can use a lookup instead of using std::underlying_type, perhaps using a hash table like this:

inline bool operator<(MyEnum left, MyEnum right) {
  static std::unordered_map<MyEnum, int> ORDER = {
    {MyEnum::A, 1}, {MyEnum::B, 2}, {MyEnum::C, 3}, {MyEnum::D, 4}
  };
  return ORDER[left] < ORDER[right];
}
Some Guy
  • 405
  • 8
  • 15
1

C++ can not sort values based on their names, only based on values, so you have to provide a mapping to the order you want it sorted. Either use a table, or a ranking function like:

enum class MyEnum { A = 3, B = 1, C = 4, D = 2};

int rank(MyEnum value)
{
    switch (value)
    {
    case MyEnum::A:
        return 1;

    case MyEnum::B:
        return 2;

    case MyEnum::C:
        return 3;

    case MyEnum::D:
        return 4;
    }
}

bool operator<(MyEnum left, MyEnum right)
{ return rank(left) < rank(right); }

And now std::sort(v.begin(), v.end()) should work for a vector of MyEnums.

You can turn the operator< into a functor and pass it to sort, if you don't want the enums compared this way other than in the sorting.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203