[C++] Appending enums / generalising enums

Started by
12 comments, last by _moagstar_ 14 years, 5 months ago
Hi, I have one Enum representing the different events that can be emitted, it's a list of possible events. So each event is a number with a compile-time name. Now I have multiple header files that all introduce new events and thus would like to give those a unique event number. I can do that with macro's of course, but that does require different enum's per time I add new events. Now, I also have classes (my signal and slot system) which depends on an enum as signal type. ATM I have templated that type. Is it OK to generalize these enums and get rid of the template type, then to replace it with unsigned int's? All events are bigger then 0, and very unlikely to exceed 4 Gi. Does anyone have a nice system to append new unique ID's to an enum? My enums are all inside their own namespace, so defining a new enum per time you add new ID's is no problem. Thanks!
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
Advertisement
Hi
I don't know about your particular situation, of course, so the following may or may not apply to you.

Why do you care about unique IDs *AND* want to have separate enums? It does not make much sense to me. I guess you should probably have one big enum. Make event handlers to care only about, well, the events they care about. (and get rid of the templated signal/slot system which might be overkill imho)
Yes, I have that setup now. The problem is that I cannot add more events from another library:

Suppose you have 2 source files and 3 header files:

base.hpp
enum Enum{    Alpha,    Beta,    Last};#define ENUM_LAST Last


header1.hpp
#include "base.hpp"enum Enum1{    Gamma = ENUM_LAST,    Delta,    Last1};#undef ENUM_LAST#define ENUM_LAST Last1


header2.hpp
#include "base.hpp"enum Enum2{    Epsilon = ENUM_LAST,    Xi,    Last2};#undef ENUM_LAST#define ENUM_LAST Last2


Now, when compiling the 2 source files which include the latter 2 header files, Epsilon == Gamma, and Delta == Xi. This is not what I want, as it will conflict elsewhere in the code.
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
I can imagine a system where you have a lazy global object that generates unique integer ID's on demand. If this object was available to all files that needed to define event ID's, you could simply assign its ID's to const ints, and it would all be taken care of at global init time.
class IDGen{    unsigned curr_id;    //you could add machinery for freeing and re-using id's    public:    IDGen():curr_id(0){}    unsigned GetId(){return curr_id++;}};//lazy global, to make sure the obj is initialized//sorta like a singleton, but less grossIDGen& idgen(){    static IDGen _idgen;    return _idgen;}//now in all the files that need id's...const unsigned EVENT_FOO = idgen().GetId();

That was even easier than I thought, but perhaps it's overkill. It is, however, a re-usable solution. The reason it came so quickly to mind is that I've been considering something similar for game object ID's.
Quote:Original post by theOcelot
I can imagine a system where you have a lazy global object that generates unique integer ID's on demand. If this object was available to all files that needed to define event ID's, you could simply assign its ID's to const ints, and it would all be taken care of at global init time.
*** Source Snippet Removed ***
That was even easier than I thought, but perhaps it's overkill. It is, however, a re-usable solution. The reason it came so quickly to mind is that I've been considering something similar for game object ID's.


Ahem ;)

Effectively, the standard allows that for every single run, all those id's are perfectly allowed to be different from the previous run. Even forks and threads of the running program might have different id's, if not shared.
I know. That's fine, as long as they are unique for the duration of the program. I guess you might have problems with threading, if the IDGen object wasn't synchronized. I admit that I don't usually bother my head with threading and related issues. But if Decrius doesn't have to either, my idea might still work.
Yes, it's a nice idea.

What if you have a global object of this running in the main thread, and any other thread asks a new ID from the main thread, there shouldn't be an issue, should there? Just make sure the counter is only ever once in memory, and only increases.

This does move the problem to a run-time issue, I would've preferred a compile-time solution, but I'm not sure if that's really possible. Except if I make a major list of all events at the top of the hierarchy of the library.
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
Quote:Original post by theOcelot
I know. That's fine, as long as they are unique for the duration of the program.


It's a nice idea, but it doesn't work. The values are not consistent.

// idgen.h#pragma onceclass IDGen{    unsigned curr_id;    //you could add machinery for freeing and re-using id'spublic:    IDGen():curr_id(0)    {}    unsigned GetId()    {        return curr_id++;    }};//lazy global, to make sure the obj is initialized//sorta like a singleton, but less grossIDGen& idgen();// idgen.cpp#include "idgen.h"//sorta like a singleton, but less grossIDGen& idgen(){    static IDGen _idgen;    return _idgen;}// foo.h#pragma once#include "idgen.h"const unsigned FOO = idgen().GetId();void foo();// foo.cpp#include <iostream>#include "foo.h"#include "bar.h"void foo(){    std::cerr << "FOO in foo.cpp : " << FOO << "\n";    std::cerr << "BAR in foo.cpp : " << BAR << "\n";}// bar.h#pragma once#include "idgen.h"const unsigned BAR = idgen().GetId();void bar();// bar.cpp#include <iostream>#include "foo.h"#include "bar.h"void bar(){    std::cerr << "FOO in bar.cpp : " << FOO << "\n";    std::cerr << "BAR in bar.cpp : " << BAR << "\n";}// main.cpp#include "foo.h"#include "bar.h"int main(int argc, char* argv[]){    bar();    foo();    return 0;}


Output :

FOO in bar.cpp : 0
BAR in bar.cpp : 1
FOO in foo.cpp : 2
BAR in foo.cpp : 3
Press any key to continue . . .
Quote:Original post by _moagstar_
Quote:Original post by theOcelot
I know. That's fine, as long as they are unique for the duration of the program.


It's a nice idea, but it doesn't work. The values are not consistent.

*** Source Snippet Removed ***

Output :

FOO in bar.cpp : 0
BAR in bar.cpp : 1
FOO in foo.cpp : 2
BAR in foo.cpp : 3
Press any key to continue . . .


You could make the declarations of the IDs in the headers extern, and define them (and assign a value from idgen()) in the corresponding source files. Then the values will be unique (but still only for one given run of the program!)
Well obviously, you include foo.h and bar.h twice each, with a resulting four calls to GetID. My system doesn't change the fact that if you want to access variables from different .cpp's, you have to extern the variables, not declare them in a header file.

This topic is closed to new replies.

Advertisement