Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Working as intended? Named combined bitflags cannot be casted to #378

Open
JWCS opened this issue Sep 6, 2024 · 2 comments
Open

Working as intended? Named combined bitflags cannot be casted to #378

JWCS opened this issue Sep 6, 2024 · 2 comments
Milestone

Comments

@JWCS
Copy link

JWCS commented Sep 6, 2024

I believe this is related to #314 and #321, so my apologies if it is. But, from the docs and those comments, it almost seemed like the below use case should work; but it fails for the BOTH case. This is after I considered your casting comments in 314 about enum vs enum_flags, and accounted for both input formats, to try both in what seemed the least restrictive way. I also read through the limitations... so I am very confused.
Working off of head (0.9.6):

#include <magic_enum_flags.hpp>
#include <iostream>
#include <string>

enum class FlowDirection : unsigned {
    NONE  = 0,
    CCW   = 1,
    CW    = 2,
    BOTH  = 3,
};
template <>
struct magic_enum::customize::enum_range<FlowDirection> {
  static constexpr bool is_flags = true;
};
inline static FlowDirection FlowDirection_read(
    std::string const& str, FlowDirection const& def = FlowDirection::NONE)
{
  return magic_enum::enum_flags_cast<FlowDirection>(str, magic_enum::case_insensitive).value_or(
      magic_enum::enum_cast<FlowDirection>(str, magic_enum::case_insensitive).value_or(def));
}

static void test(std::string const& str){
    FlowDirection flow = FlowDirection_read(str);
    std::cout << str << " ("
      << magic_enum::enum_name(flow) << "/"
      << magic_enum::enum_flags_name(flow) << "): "
      << magic_enum::enum_integer(flow) << std::endl;
}

int main(){
    test("CCW");
    test("ccw");
    test("cw");
    test("BOTH");
    test("NONE");
    test("NONE|CCW");
    test("CCW|CW");
    return 0;
}

Which results in incorrect values definitely for BOTH, and a curious non-parsing (?) for "NONE|CCW"

> g++ -std=gnu++17 demo.cpp && ./a.out
CCW (CCW/CCW): 1    # OK
ccw (CCW/CCW): 1    # OK
cw (CW/CW): 2       # OK
BOTH (/): 0         # Uhhhhh help?? I have no clue what I'm doing wrong, to not get this.
NONE (/): 0         # This is interesting; the value is correct, but the name is missing; which might be 321
NONE|CCW (/): 0     # Uh, I don't think I need this, but, is this a bug?
CCW|CW (/CCW|CW): 3 # OK
@Neargye Neargye added this to the v0.9.7 milestone Oct 14, 2024
@Neargye
Copy link
Owner

Neargye commented Oct 14, 2024

BOTH (/): 0 - #314 (comment). BOTH is not true flag, it is a "flag or"

NONE (/): 0 - #321

NONE|CCW (/): 0 - will check, looks like bug, expected 1

@JWCS
Copy link
Author

JWCS commented Oct 14, 2024

With respect to the first one, BOTH, the reason for my confusion is that the read() function attempts both (in order) enum_flags_cast and then enum_cast.
As per the relevant docs/comment in 314:

enum class TestEnum {
A = 0,
B = 1,
C = 2,
D = 3,
};

enum_name(TestEnum::D) = 'D'; vs enum_flags_name(TestEnum::D) = 'B|C';
enum_flags_cast('A') = nullopt; vs enum_cast('A') = TestEnum::A;
enum_flags_cast('D') = nullopt; vs enum_flags_cast('B|C') = TestEnum::D; vs  enum_cast('D') = TestEnum::D;

I'd expect enum_flags_cast('D' /* BOTH */).value_or( enum_cast('D') to fail on flag-cast D (since not a real flag), but then trying to normal enum cast D to work (enum_cast('D') == TestEnum::D) (and the resulting integer TestEnum::D == TestEnum::B | TestEnum::C).
I tried it like this, such that if the string 'B|C' was passed, that would first get correctly parsed/handled, but if the shorthand 'BOTH' was passed, that would also get correctly handled.
My main question is, is there something I'm missing, that test("BOTH") ->
enum_flags_cast("BOTH") /* fail */ .value_or( enum_cast("BOTH") /* fail */ .value_or("NONE") /* incorrect!? */ ).
Does it have something to do with

template <>
struct magic_enum::customize::enum_range<FlowDirection> {
  static constexpr bool is_flags = true;
};

?

@Neargye Neargye modified the milestones: v0.9.7, v0.9.8 Nov 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants