3

I have an enum, but I want to have an assignment operator for it to be able to assign a type that is not of the original enum. E.g.

enum class X : int
{
  A, B, C, D
}

enum class Y : char
{
  A, B, C, D
}

Y& operator=(Y& lhs, X rhs)
{
  return Y = static_cast<Y>(X);
}

But I'm getting an 'operator =' must be a non-static member. Is there no way to do this?

cpplearner
  • 13,776
  • 2
  • 47
  • 72
Adrian
  • 10,246
  • 4
  • 44
  • 110
  • I can't imagine a good use case for this. Can you help me out? – Lightness Races in Orbit Apr 04 '16 at 20:27
  • @BarryTheHatchet, the case for this is that I'm trying to update some archaic code. They use the same constants in two different spots, but in one, it has a size of 1 byte and another it has a size of 2. I'd rather not change the binary compatibility of the structures in case that breaks something. – Adrian Apr 04 '16 at 20:33
  • If you refer to the original code as archaic, I'm guessing it's not using `enum class`, I'm guessing that's a modification you made. Is that correct? If so, would some alternative that does not use `enum class` also be acceptable? –  Apr 04 '16 at 20:35
  • @hvd, It is using `int` and a `char`, not even an enum. – Adrian Apr 04 '16 at 20:36
  • 1
    Then Brian's answer is exactly what I would've posted. I'd give up on `enum class` if I were you, you can achieve what you want without it. –  Apr 04 '16 at 20:40
  • Me too. So, you see why I asked. :) – Lightness Races in Orbit Apr 04 '16 at 20:49
  • @hvd, yeah, but it is annoying. No one would have expected a use case like that. – Adrian Apr 04 '16 at 21:28
  • Turns out this won't help. Some of the code is written in C and no C++. This would then require that I somehow get the VC compiler to compile the C code in C++, which could do a whole lot of unexpected things that I am not prepared to deal with at the moment. – Adrian Apr 04 '16 at 22:19
  • Does this answer your question? [Is it possible to manually define a conversion for an enum class?](https://stackoverflow.com/questions/12753543/is-it-possible-to-manually-define-a-conversion-for-an-enum-class) – M.J. Rayburn Jan 16 '20 at 04:59

3 Answers3

8

You cannot because, as the error message tells you, operator= can only be a non-static member function, and enums can't have members. If you really want to be able to assign from a different enum, maybe you should just make Y a class. Another possibility is to write a helper function to perform the assignment.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Hmmmm, that's unfortunate. :( Making `Y` a class could make even more trouble in terms of typing... – Adrian Apr 04 '16 at 20:41
  • 1
    @Adrian typing is not trouble. hidden logic errors is trouble. implicit conversions hide subtle logic errors. – Richard Hodges Apr 04 '16 at 21:48
  • By typing trouble, I mean that I'll have a 2 types per enum (class and enum) with the enum being on the 2nd level. Which isn't horrible I guess, but annoying. `class ByteX { enum X { A, ... }; }; class WordX { enum X { A, ... }; }; class DWordX { enum X { A, ... }; }; void fn() { DWordX x = WordX::X::A; }`. Or I guess they can all reference the Byte one, or have the Byte enum defined externally... – Adrian Apr 04 '16 at 21:59
3

An enum class is a cumbersome structure you may avoid. Just wrap an old enumeration inside a structure:

#include <iostream>

struct X
{
  enum enum_type { A, B, C, D };
  typedef int value_type;
  value_type value;

  X(enum_type value) : value(value) {}
  operator enum_type () const { return static_cast<enum_type>(value); }
};

struct Y
{
  enum enum_type { A, B, C, D };
  typedef char value_type;
  value_type value;

  Y(enum_type value) : value(value) {}
  operator enum_type () const { return static_cast<enum_type>(value); }

  Y& operator = (X rhs) {
    value = rhs;
    return *this;
  }
};

int main()
{
    X x = X::A;
    Y y = Y::B;
    std::cout << y << '\n';
    y = x;
    std::cout << y << '\n';
}
  • 1
    Don't encourage hacks instead of clean solutions. An enum class is exactly what you need if you want scoped enums. Write a helper function, it's a lesser hack. – szali Dec 10 '19 at 11:38
0

You may write an conversion function rather than an conversion operator. In any case this is better form as it expresses intent clearly at the call site.

enum class X : int
{
    A, B, C, D
};

enum class Y : char
{
    A, B, C, D
};

Y to_y(X rhs)
{
    auto as_int = static_cast<int>(rhs);  // allowed
    auto as_char = static_cast<char>(as_int); // allowed if the int is known to fit
    return static_cast<Y>(as_char); // allowed if the char is known to be the right value
}

int main()
{
    auto x = X::C;

    auto y = to_y(x);

    return 0;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Thanks, but I wanted it implicit as this is going to be everywhere. – Adrian Apr 04 '16 at 21:44
  • if it's going to be everywhere, you absolutely do not want it to be implicit. – Richard Hodges Apr 04 '16 at 21:47
  • Yeah, I do. The conversion is only from type `X` to type `Y` and back. They represent the same information, but in different sizes. They will never overflow each other. There's absolutely no reason why it shouldn't be implicit. – Adrian Apr 04 '16 at 21:49
  • so use an old-style `enum` rather than an `enum class` – Richard Hodges Apr 04 '16 at 22:01
  • No, I don't want implicit conversion to a numeric. Only to a type of my specification. – Adrian Apr 04 '16 at 22:07
  • So use an old-style `class` with conversion and assignment operator(s). – Spencer Apr 04 '16 at 23:01
  • I understand where he's coming from. I love enum classes for their identity building uses. Rather than just "type safe", they are "purpose safe". And they are very flexible in almost every way, except for implicit conversion between "purposes". It's something I would imagine being added to the standard in the future. – Robert Dec 19 '22 at 21:52