Neargye / magic_enum

Static reflection for enums (to string, from string, iteration) for modern C++, work with any enum type without any macro or boilerplate code
MIT License
4.88k stars 434 forks source link

Initialize a containers::bitset with an integer #286

Closed labankallgren closed 1 year ago

labankallgren commented 1 year ago

Is there anyway to initialize a bitset with an unsigned integer value?

int v = 10;
auto mask = containers::bitset<T>{v); // 1010
Neargye commented 1 year ago
auto mask = containers::bitset<T>(enum_cast<T>(v).value());
// more safe
int v = 10;
auto m = enum_cast<T>(v).value();
auto mask = containers::bitset<T>(m.has_value() ? m.value() : T{0});
labankallgren commented 1 year ago

I would say that it is not the behavior I expect from initializing from an unsigned integer value. See my example:

enum class Color { Red, Green, Blue, Yellow, Cyan, Magenta };
// Red is LSB

int main() {
  uint v = 10;  // 1010 -> Green | Yellow
  const containers::bitset<Color> expected_mask{Color::Green, Color::Yellow};

  auto m = enum_cast<Color>(v);
  std::cout << "Color enum has a value: " << std::boolalpha << m.has_value() << std::endl;

  auto mask = containers::bitset<Color>({m.has_value() ? m.value() : Color{0}});

  std::cout << "Expected mask: " << expected_mask << std::endl;
  std::cout << "Mask: " << mask << std::endl;
  assert(mask == expected_mask);
}

Output:

Color enum has a value: false
Expected mask: Green|Yellow
Mask: Red
a.out: testmagicenum.cpp:21: int main(): Assertion `mask == expected_mask' failed.

I don't think one should cast the integer value mask to an enum value first as it will fail in the cases where not just one bit is set. There must be a constructor on containers::bitset that accepts a uint bit mask value.

Neargye commented 1 year ago

Could you try this

auto mask = containers::bitset<T>(enum_flags_cast<T>(v).value());

Will work if enum is flags

labankallgren commented 1 year ago

Yes, the above proposal for a solution works!

Neargye commented 1 year ago

I advise you to use this solution for now. I will look at the possibility to extend the API directly in the container