better-enums icon indicating copy to clipboard operation
better-enums copied to clipboard

Traits class

Open cheparukhin opened this issue 9 years ago • 15 comments

I would be nice to have a traits class to detect whether a type is a "better enum" (akin to std::is_enum)

cheparukhin avatar Jun 21 '16 18:06 cheparukhin

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 avatar Jun 21 '16 23:06 aantron

@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 {};

cheparukhin avatar Jun 21 '16 23:06 cheparukhin

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 avatar Jun 21 '16 23:06 aantron

@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?

cheparukhin avatar Jun 21 '16 23:06 cheparukhin

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.

aantron avatar Jun 22 '16 00:06 aantron

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.

aantron avatar Jul 07 '16 20:07 aantron

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.

ecorm avatar Mar 07 '17 21:03 ecorm

Could extra/better-enums/n4428.h be used for this purpose?

ecorm avatar Mar 07 '17 21:03 ecorm

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.

aantron avatar Mar 07 '17 22:03 aantron

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.

ecorm avatar Mar 07 '17 23:03 ecorm

+1 for deriving the types from a common base type, so I can develop functionality that works on all enum types without using templates!

tallavi avatar Sep 20 '17 19:09 tallavi

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

morgoth990 avatar Sep 26 '18 15:09 morgoth990

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.

Xeverous avatar Mar 04 '19 00:03 Xeverous

Noted! I really need to get around to doing this.

aantron avatar Mar 11 '19 21:03 aantron

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?

gri6507 avatar Nov 04 '22 02:11 gri6507