Dynamic list of variables?

Started by
11 comments, last by Foofles 13 years, 8 months ago
Hey everyone,

I decided to rework one of my projects and I figure I might as well employ some kind of functionality that would allow me to say:

RegisterVariable("VariableName", Type), SetVariable("VariableName", value), GetVariable("VariableName"), etc. etc.

Something that would be fully scalable in the future.

So I'm basically wondering what's the best way to go about this? I currently have a sort of std::string / boost::any map going on right now, with templated functions for Get and Set... but this seems incredibly messy and ripe for disaster.

To correctly use it I have to explicitly cast the calls. I don't like it and it seems non-modular. Any advice?

Should I limit my engine to a few basic types?
Advertisement
What are these variables going to be used for? Some kind of in game console, or scripting, or?
Quote:Original post by rip-off
What are these variables going to be used for? Some kind of in game console, or scripting, or?



A bit of both.

Things like core engine settings, game settings, rendering settings, user settings... sort of the server vars / client vars format is what I want to go after.
Quote:Original post by Foofles
A bit of both.

Things like core engine settings, game settings, rendering settings, user settings... sort of the server vars / client vars format is what I want to go after.
It seems to me this is the sort of thing that would be best (or at least better) handled in a scripting environment (e.g. via Lua). If you want to do it on the C++ side though, a container of boost::any, boost::variant, or a similar custom container would probably do the trick. (Which is what you're doing currently, of course, and given appropriate error-checking and so on, I don't see any particular problem with this approach. It doesn't necessarily seem messy or 'ripe for disaster' to me :)

Another option would be just to store the values as text, and (attempt to) cast them to specific types on request. (This could have performance implications though if for some reason you needed to access a setting in a tight inner loop. In that case though, you could probably simply cache the value for the duration of the function.)
Thanks for the reply!

I guess I just figured there might be a better way, right now I basically do a check of the templated return type vs some types and if it matches I do the boost::any_cast to return, or I throw an error to the engine / return null / etc.

One reason I figure this is messy is how do I deal with things like differing types of similar contexts... like int vs short vs long.

I think cpp automatically casts all integers to typeid int, like if you just type a number in, but that starts to get messy if I want to deal with shorts, longs.... should I just not deal with them? Should I limit integer access to typeid int? Is doing a typeid() comparison stupid? Because that's what I'm doing and it feels so wrong.
Quote:I guess I just figured there might be a better way, right now I basically do a check of the templated return type vs some types and if it matches I do the boost::any_cast to return, or I throw an error to the engine / return null / etc.

One reason I figure this is messy is how do I deal with things like differing types of similar contexts... like int vs short vs long.

I think cpp automatically casts all integers to typeid int, like if you just type a number in, but that starts to get messy if I want to deal with shorts, longs.... should I just not deal with them? Should I limit integer access to typeid int? Is doing a typeid() comparison stupid? Because that's what I'm doing and it feels so wrong.
I think the different versions of any_cast() have ways of communicating to the caller that the cast failed (e.g. throwing an exception if the input value is a reference). Couldn't you use this to determine whether the cast is valid, rather than comparing types directly? It seems that would be more straightforward.

I don't see why storing different integer types would introduce any special considerations, but I'm also not sure why you'd need to store different integer types in the context of a console and/or settings system. (Aside maybe from signed and unsigned, I suppose.)

Can you give an example of where it would be advantageous for a setting to be a short rather than, say, a long?
Well, you're right that I mainly would want to isolate the unsigned long from a regular signed int, I don't have any reason to prefer a short over a long, I guess I'm saying I didn't want it to be confused if it got type short as input, that it would cast appropriately... but you mention something that sounds cleaner, I will look into it, thanks so much
I'm not really sure what advantages you think you'll have by making these variables and their types data-driven, short of using them in an actual scripting language. The code has to make assumptions about which variables exist and their type anyway, so wouldn't it be easier to just make them proper C++ variables in a struct somewhere? The reason I wonder is because I've gone down the "generic variable system" route before and other than being somewhat cool, it really didn't give me anything more than extra work when interacting with those variables.
I think I should've actually looked at my code more before posting (I stopped working on the project a few months ago for lack of time)

I don't do a typeid comparison in my "GetVariable", I do just see if the cast threw an exception. The typeid was from my attempts to output the boost::any to a stream, however I just discovered boost::spirit::hold_any and it has native stream operator support so that solves that problem. :)

Zipster, yeah I know what you mean. I've been on the fence of implementing something like this for a while and I still can't shake that no matter what it feels messy and bloated. It does seem a little awkward to use compared to using global engine variables like I did before for settings type things.

I don't know if the overhead is going to be worth it or not. Maybe I should just do all the variables in the more straightforward way, I can always use .dlls in the future to add new game variables with the game data.

Thanks for the replies guys :)

[Edited by - Foofles on August 22, 2010 10:32:43 AM]
I really think you should look at adding a scripting system. Lua is really easy to embed in C++. The only really annoying thing to do is passing userdata types in and out of Lua, but you can automate that with templates.

This topic is closed to new replies.

Advertisement