-
Notifications
You must be signed in to change notification settings - Fork 452
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
Should enum_name(E value) (and maybe others?) be prevented from working with empty enums? #320
Comments
For full disclosure - my current guess for the root cause was that the refactoring accidentally introduced an ODR violation. The code that was pulled out was missing the include for the enum, so Having |
Hi,
What do you think about it? |
I think that approach sounds reasonable, especially if backwards compatibility is a concern. Macros to disable the asserts are a nice suggestion as well.
One alternative I can think of is a custom override similar to `is_flags` (`is_empty`?). That way the library can generally assume non-empty enums are used, but end users can override that assumption for specific empty enums so they still get the sanity checks for other enums in their code. I think this should still catch accidental use of forward-declared enums, so I don't believe it sacrifices anything.
Edit: Fixed mangling from email reply
|
I am doing something similar on purpose: // Forward declare (values are intentionally deferred until after the
// names TESTs are defined):
enum MyModuleTapNames: uint32_t;
// later, in the .cpp file:
enum MyModuleTapNames {
Foo,
Bar,
}; This allows me to hide the definitions from all translation units except the one that cares about it, and erase type information to generically have a system to grab enum names and counts from each translation unit.
We should distinguish here between If there's some technical restriction that prevents distinguishing the two cases, then let me know. |
At least based on some cursory searches it seems a fully conforming generally-useable That's part of why I suggested an |
@ts826848 @thirtythreeforty Please check this PR for possible solution #323 |
This partially works for me. It does correctly reject a declaration like enum class MyEnum; But, it does not reject a declaration that includes the underlying type: enum class MyEnum: uint32_t; |
The PR catches the error that I originally ran into, so I think it works for me. I think it should work for most others users as well; the only exception would be if a user intentionally has both empty and non-empty enums but prefers to keep the checks for non-empty enums if possible. I don't know whether that case will come up at all, though, and I think allowing checks to be done on a case-by-case basis should be fairly straightforwards. I've left a few comments on the PR as well, but they're pretty much nitpicks.
That's strange. The check is just #include "include/magic_enum/magic_enum.hpp"
enum class Forward : uint32_t;
auto f(Forward f) { return magic_enum::enum_name(f); } I get a |
Ah, sorry. You are correct. I was relying on CLion's static analysis rather than running a build. I see your described behavior on Clang 16 and GCC 13.2. So it is working for me! Thank you! |
I just finished helping a colleague track down some strange test failures that appear to stem from
enum_name(E value)
unintentionally behaving as ifE
were an empty enum. It took a bit to track down this specific issue because the code that actually usedenum_name(E value)
wasn't touched in the problematic commit. Some other unrelated shuffling of code appears to have confused the compiler so it started treating the enum in question as a plain forward declaration rather than its full definition, soenum_name(E value)
was returning empty strings instead of the correct names.This got me thinking - should
enum_name(E value)
work at all if the enum is empty?enum_name<auto V>()
has astatic_assert
to bail if the returned name is empty, so changingenum_name(E value)
to bail on empty enums and/or empty names would arguably make the behaviors match and could help catch unintentional changes like this where a previously-defined enum starts being treated as a forward declaration.I think this question could also be extended to other parts of what magic_enum offers, but
enum_name
is definitely the place where I've experienced issues the most.And if
enum_name(E value)
should work with empty enums, should it return astd::optional<std::string_view>
to distinguish between the "no name due to invalid value/empty enum" and "empty name" cases?The text was updated successfully, but these errors were encountered: