better-enums
better-enums copied to clipboard
Traits class
I would be nice to have a traits class to detect whether a type is a "better enum" (akin to std::is_enum)
Agreed, this would be nice. However, I don't think I can just do it in the obvious way, using template specialization:
namespace better_enums {
template <typename T>
struct _is_better_enum_value {
constexpr static const bool value = false;
};
template <typename T>
struct is_better_enum : public _is_better_enum_value<T> {
// Standard members: type, value_type, operator bool, operator ().
};
}
// The specialization, generated by the macro...
template <>
struct _is_better_enum_value {
constexpr static const bool value = true;
};
because the specialization does not occur, in general, in a namespace that encloses the original template declaration. So, if you do
namespace my_ns {
BETTER_ENUM(Foo, int, bar)
}
you will get an error, since my_ns is not better_enums or the global namespace.
There is probably some way to do this with SFINAE, by checking a specially-named member of generated enums. This is a bit fragile, but should be pretty easy in C++11. I am not sure if it can work in C++98, though – C++98 is a bit out of my brain's cache right now.
I'm a bit overwhelmed by other work at the moment, but I will look into it later. You are welcome to comment as well :)
@aantron I currently implemented it in my code using SFINAE checking _to_integral member function, but it seems a bit hacky. I was wondering if you can derive enum classes from a common base and then use std::is_base_of to check if a class is an enum.
#include <type_traits>
#include <utility>
template <typename T, typename = void>
struct IsBetterEnum
: std::false_type {};
template <typename T>
struct IsBetterEnum<T, decltype(std::declval<T>()._to_integral(), void())>
: std::true_type {};
All those could work, but if implemented literally that way, they would require C++11. While I've been thinking on and off about dropping C++98 support, I think it's better to keep it for as long as reasonably possible.
I'm pretty sure std::is_base_of, or a type member check, or something, can be implemented using only C++98 constructs – I'm just so out of practice with C++98, and constrained, that I can't do it in the really near future :/ If you can adapt your approach above to something that doesn't use <type_traits>, decltype, and so forth, and compiles with your compiler's C++98 flags, a PR would be very welcome :)
Deriving all enums from a base class should be fine. Adding some less collision-prone member value or type, such as _is_better_enum, is also fine.
@aantron I've only been using C++11 for the last 5 years at least, so I don't think I can help with C++98. I wonder if there's any particular reason for C++98 support? I can hardly imagine someone using it for new code nowadays :) Could it be provided as C++11-only feature?
Yep, it can be provided as a C++11-only feature, and might have to be. I'd still like to try to adapt it to C++98 first, though, so If you don't mind the upstream not having this for a while, then let me get around to it. It's definitely on the list of things I want to add :)
As for C++98, I think a lot of people are stuck in old code bases. They might still want a nicer enum :)
I'm actually planning to take advantage of some C++14 features, too, when I next have the time for a burst of work on Better Enums. I may be removing C++98 at that point, if supporting all 3 standards gets too cumbersome.
Following on #22, if MSVC has had a <type_traits> supporting the features we need, and whatever combination of decltype and/or declval, for "long enough" (since, maybe, mid-2015), we can move away from needing a C++98 implementation, and implement the traits class you are requesting using those C++11 features. If you can confirm that, then a PR/commit is very welcome.
For those of use willing to use C++11 features, is there a way we can write our own macro that wraps BETTER_ENUM and provides the necessary plumbing for a is_better_enum<T>::value trait? The lack of such a is_better_enum<T>::value trait is preventing us from replacing our hand-written enum<-->string maps with your library.
Could extra/better-enums/n4428.h be used for this purpose?
You should be able to write ordinary variable-argument macros wrapping BETTER_ENUM that do any extra work that you need. Are you having difficulties with that?
In the meantime, I'm tending towards finally dropping C++98 the next time I have hours to work on Better Enums.
You should be able to write ordinary variable-argument macros wrapping BETTER_ENUM that do any extra work that you need. Are you having difficulties with that?
I haven't tried yet. I never had to write variable-argument macros before and just wanted to check that it was even possible before attempting it.
+1 for deriving the types from a common base type, so I can develop functionality that works on all enum types without using templates!
deriving the types from a common base type can help me too, I'm working on a generic object inspector and is the only way to draw a generic gui without manage every specific enum type from code
Just a bump noting that there are more people interested in is_better_enum trait. I was surprised when I realized that std::is_enum_v<BetterEnumType> == false. This means that the "upgrade" from C++11 enums to better enums can actually result in build failures.
Noted! I really need to get around to doing this.
I am also interested in this functionality. I see that this issue was added to 0.11.3 milestone, but 0.11.3 is already released. Does this mean that this feature has not been implemented yet?