Jump to content
  • Advertisement

antron

Member
  • Content Count

    0
  • Joined

  • Last visited

Community Reputation

311 Neutral

About antron

  • Rank
    Newbie
  1. @SmkViper: TL;DR: The generated struct can be made to use enum class, and you can set the size either way. So, it doesn't have those issues The long version follows:   The generated struct is actually almost as type-safe as enum class by default. Wrapping in a struct already guarantees a lot of type safety on its own. The only "hole" is implicit conversions to int, which is a side effect of how I enable direct usage in switch. I address this hole in two ways:   First, this is a much lesser evil than being able to convert from int to enum. Even with this hole, you are still guaranteed the same constraints as enum class on how enum values are introduced. You just can't prevent their usage in contexts that don't expect an enum.   Second, in case that argument is not acceptable, there are some simple instructions you can follow to cause the macro to use an enum class internally instead. It then becomes equally as type-safe as enum class, but at the cost of having to write + characters in switch cases.   On top of that, I would argue that, in another way, this macro is more type-safe than either enum or enum class, since the generated struct does not have a default constructor unless you enable it. This prevents unintended zero-initialization or "initialization" with arbitrary values. It gives you more control over how and where enum values are introduced than built-in enums can provide, so you can be even more sure your enums are valid and invariants are being maintained.   In general, I take type safety very seriously. I decided these choices were the most balanced defaults, but of course, these are just my opinions – hence the ability to toggle them  I'm also happy to hear feedback. If people tend to disagree, I will change the defaults.   And, you can set the size of the enums. That's what the second argument to the macro is doing In fact, you can't not set the size of the enum. The limitation is that you always have to choose it But I figured it's easy enough for people to just type "int" if they have no particular need for anything else.   The solution you propose with the side-by-side enum and struct is a good and valid one. I've been referring to it as the type traits approach, where the macro generates a regular C++ enum class, and next to it an instance of a template struct containing arrays and a bunch of functions. Instead of being related by name, however, they are related by the enum being the template argument of the struct. So, if you have an enum class State (declared through the macro), you can list its values by accessing enum_traits<State>::values(), etc. You don't lose much by not being able to call functions on instances of the enum – most of the generated functions are static either way.   I have some discussion in the docs as to why I chose (so far) not to do it that way, and there is also an old branch on GitHub that has a demonstration of what the traits implementation might look like. Note that this branch is really outdated relative to master in terms of overall quality. I still think that the question of wrapping in a struct vs. generating a struct alongside is an open one, though, and I'd be glad to hear any comments you have on it.   Both approaches, however, are able to provide a strict superset of the features of enum class, including in the area of type safety. In fact, if you are limited to C++98, the wrapping approach actually brings several enum class features.   I realized that the pseudocode struct in the article was a little misleading on the matter of size, so I updated it.
  2. @TookieToon: Thanks. I'd be curious to know how it turns out if you try it with Lua.   @swiftcoder: I used a couple scripts and LICEcap to capture the actual GIF, but I'm sure any capture program would work. I first wrote a little local web page with a single text area and JavaScript that listens to input events and converts them into a series of time index, letter pairs – this records my typing, and then outputs it as an OCaml list. I then wrote a little OCaml script to play those lists back, together with output, in the terminal. After that, I used LICEcap to make the actual GIF. I guess it's working :)
  3. Thanks, all   @imoogiBG: The compile times are pretty good. For the library, I run comparisons, where I compare including iostream (and not using it) with including enum.h and declaring lots of enums using the macro. Depending on the compiler, you need to generate about 20-30 enums to take up as much time as handling iostream does. Clang is the fastest at the moment. So, while the macro is *much* slower than built-in enums, it is still much faster than parts of the standard library. You can see details here.   @rnlf: I do hope some combination of reflection proposals makes it into C++17.   For now, I "implemented" the enums portion of N4428, but the implementation still requires that the enum be declared with the macro. It's mostly just an exercise, and not very practical – but details are here.
  4. Background Enums are used in game programming to represent many different things - for example the states of a character, or the possible directions of motion: enum State {Idle, Fidget, Walk, Scan, Attack}; enum Direction {North, South, East, West}; During debugging, it would be useful to see "State: Fidget" printed in the debug console instead of a number, as in "State: 1". You might also need to serialize enums to JSON, YAML, or another format, and might prefer strings to numbers. Besides making the output more readable to humans, using strings in the serialization format makes it resistant to changes in the numeric values of the enum constants. Ideally, "Fidget" should still map to Fidget, even if new constants are declared and Fidget ends up having a different value than 1. Unfortunately, C++ enums don't provide an easy way of converting their values to (and from) string. So, developers have had to resort to solutions that are either difficult to maintain, such as hard-coded conversions, or that have restrictive and unappealing syntax, such as X macros. Sometimes, developers have also chosen to use additional build tools to generate the necessary conversions automatically. Of course, this complicates the build process. Enums meant for input to these build tools usually have their own syntax and live in their own input files. The build tools require special handling in the Makefile or project files. Pure C++ solution It turns out to be possible to avoid all the above complications and generate fully reflective enums in pure C++. The declarations look like this: BETTER_ENUM(State, int, Idle, Fidget, Walk, Scan, Attack) BETTER_ENUM(Direction, int, North, South, East, West) And can be used as: State state = State::Fidget; state._to_string(); // "Fidget" std::cout
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!