Avoiding a long chain of if-else if blocks

May 22, 2009 at 12:22am
In a game I am working on, I have had a long chain of if/else if blocks to compare a command the player has entered with some strings representing valid commands. I then run the applicable function.

1
2
3
4
     if(input == "com1") func1();
else if(input == "com2") func2();
else if(input == "com3") func3();
// and so on 

I'm sure there is a better way to do this; especially since eventually MSVC++ is going to complain once I get over a certain number of nested statements. One idea I had was to load from a file that contained valid commands followed by the name of the function to run; I could store those as a vector of pairs or a map, etc. and then use a simple for loop to call a function pointer to the right function.

Example file:
com1 func1
com2 func2
com3 func3

The only issue is that I'm not certain how (or if) I can convert the string name of the function loaded from the file into the address of the function. If this isn't possible, does anyone have any ideas as to how I could accomplish the input string comparison without use the if/else if chain?

I was going try a method similar to my idea: hash the function names to an integer and use a switch/case, which would (I believe) avoid the nested if/else problem, but I was using the boost hashing system which doesn't create hashes for constants at compile-time, and couldn't be used in a case statement.

I apologize if I was unclear anywhere; ask for clarification if I didn't make any sense somewhere. Any input for my problem is welcome at the moment.
May 22, 2009 at 12:48am
1
2
3
4
5
6
7
8
typedef std::map<std::string,/*function pointer type*/> map_t;
map_t command_list;
command_list["com1"]=&func1;
//...
map_t::iterator i=command_list.find(command);
if (i==command_list.end())
    //command doesn't exist
(*i->second)(/*parameters*/);


Not only does this avoid nested ifs, but it's also faster. The average time complexity of nested ifs is O(n). The time complexity of std::map::find() is always O(log n).
Last edited on May 22, 2009 at 12:51am
May 22, 2009 at 12:53am
That makes sense; however my original intent for creating the file was to avoid having to hard-code a large constant map like that. xD But if there isn't any other similarly simple option, then I suppose it will have to do.
May 22, 2009 at 12:57am
The problem with your dynamic approach is that C++ is not reflective. In other words, the symbols are not available at run time, so you can't do something like call a function based on a string, which means you'd still have to convert the string "func1" into a pointer to the function func1() by some means. So it doesn't solve the problem, it only moves it.
May 22, 2009 at 1:07am
Right, and I figured that was impossible. For now, I'll just hard-code the map since it is definitely better than if/else.
Topic archived. No new replies allowed.