Jump to content
  • Advertisement
Sign in to follow this  
darenking

Switch statement in C++ with strings?

This topic is 4826 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Howdy! I'm writing a routine that triggers the loading in of sprites (or tile images or whatever) by reading instructions from a text file. The text file contains instructions like this: loadsprites data/001_sprites_paula.bmp loadsprites data/001_sprites_smally.bmp I wanted to do a switch statement like this:
		file.getline(text, 100);

		switch (text)
		{
			case "loadsprites":
				file.getline(text, 100);
				CreateSprites(text);
				break;

			case "loadtiles":
				file.getline(text, 100);
				CreateTiles(text);
				break;

			default:
		}

...so that when it finds the instruction 'loadsprites' it will load in the bitmap named in the next line. But it seems you can't do a switch statement with a string of characters! Any ideas?

Share this post


Link to post
Share on other sites
Advertisement
switch does not work with strings, only integral types. see link for details

try this instead.


if (strcmp(text, "loadsprites") == 0) {
[...]
} else if (strcmp(text, "loadtiles") == 0) {
[...]
} else {
[...]
}

Share this post


Link to post
Share on other sites
Depends how extendable you want your system to be. I did something kind of similar in my last project, as I had a quake like console, which could execute commands typed in by the user. The way I implemented it, was to have the console store an array of Command objects. Each command had a method which accepted an array of arguments, and a method that returned a unique integer hash value generated from the commands name.

When the command line is parsed, the console generates a unique hash code from the command name typed in at the command line, and searches its list of commands for a
command that has a matching hash code (and therefore a matching name).

To generate the hash code, I used the CRC32 algorithm. There's an implementation of it in the boost library.

If you don't want to go that far, then something like this would probably suffice.



//Do this once at initialisation time
UInt loadSprites = GenerateHash ( "LoadSprites" );
UInt loadTiles = GenerateHash ( "LoadTiles" );



//At load time
commandName = GetCommandNameFromFile();
UInt commandHash = GenerateHash ( commandName );

switch ( commandHash )
{
case loadSprites:
//Blah

case loadTiles:
//What
}





If you're interested in seeing how I implemented my solution, then the source code to my old project is available here. I think Console.h and Console.cpp are the relevant files. ConsoleCommand.h and ConsoleVariable.h might also be of interest.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
NO! :P

Share this post


Link to post
Share on other sites
Quote:
Original post by darenking
Thanks for that reply. That will do the job just fine, but does anyone know of any other solutions?


you could use a std::map< string, enum/int> and simply do a lookup.

Share this post


Link to post
Share on other sites
A common way of solving this, is to first convert your string to a numeral like this:

#define INSTRUCTION_TYPE_LOADSPRITES 1
#define INSTRUCTION_TYPE_LOADTILES 2
#define INSTRUCTION_TYPE_UNKNOWN 3

int GetInstructionType(char *text)
{
if (strcmp(text, "loadsprites") == 0) {
return INSTRUCTION_TYPE_LOADSPRITES;
} else if (strcmp(text, "loadtiles") == 0) {
return INSTRUCTION_TYPE_LOADTILES;
} else
return INSTRUCTION_TYPE_UNKNOWN;
}


and then change your switch statement as follows:


file.getline(text, 100);

switch (GetInstructionType(text))
{
case INSTRUCTION_TYPE_LOADSPRITES:
file.getline(text, 100);
CreateSprites(text);
break;

case INSTRUCTION_TYPE_LOADTILES:
file.getline(text, 100);
CreateTiles(text);
break;

default:
break;
}


It could be made even nicer by using an enum, but this should be clear enough.

Note that if you have to compare the same instruction string many times, this conversion to an integer is also faster, because you'll need only one string comparison to get the int.

Tom

Share this post


Link to post
Share on other sites
You could try something like this:

typedef void (*CreateFunc)(std::string text);

std::map<std::string, CreateFunc> lookuptable;
lookuptable["loadsprites"] = CreateSprites;
lookuptable["loadtiles"] = CreateTiles;

std::string input = std::getline(file);

if(lookuptable.count(input) <= 0) {
// Error! Invalid command
}

std::string text = std::getline(file);
lookuptable[input](text);

I haven't used C++ in a while, so this might not be completely correct.

EDIT:
Wow, I should really stop taking so much time to post.
Quote:

Depends how extendable you want your system to be. I did something kind of similar in my last project, as I had a quake like console, which could execute commands typed in by the user. The way I implemented it, was to have the console store an array of Command objects. Each command had a method which accepted an array of arguments, and a method that returned a unique integer hash value generated from the commands name.

For the love of god, no! A std::map should do just fine without complicating everything like that. Even if it turns out you need to hash the strings, you should probably use something like std::hash_map.

Share this post


Link to post
Share on other sites
EDIT: I am mindnumbingly slow.

Or you could do another way, for instance:


// A function pointer that represent script functions
typedef void (*scriptFunction)(std::istream&);

// A context: it associates a name (the function name or the variable name)
// with an object (a script function)
typedef std::map<std::string,scriptFunction> context;

void CreateSprites(std::istream&);
void CreateTiles(std::istream&);

// Parsing a script document:
void parse( std::istream& in ) {

context c;
c["loadsprites"] = CreateSprites;
c["loadtiles"] = CreateTiles;

string command;

while( !std::getline( in, command ) ) {

c[command](in);
}
}


Note: the above is unsafe, you should always check that c[command] is an actual function, or your script can make your program crash.

Additional advantages: if you replace the function pointer by a (non-pointer) object, you can do just about anything.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!