Jump to content
  • Advertisement
Sign in to follow this  
suliman

c++ function parameters: sending two different string with extra %.0f %d

This topic is 2499 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

Hi
I have a function

void gameGFX::write(int flags,long x, long y,int align,const char *fmt, ...){

That can take a string and manipulate it by inserting %d for intigers etc and then draws it to the screen. I want to modify it so it can take two different string and then from a variable "bool useAlternativeLanguage" decide which string to use WHILE maintaining the possiblity to send numbers, strings etc to be added.


gfx.write(0,20,170,0,"Residential pop %.0f","Other language string pop %.0f",currentCity.pop[1]);


How would I go about solving this?
Thanks a lot
Erik

Share this post


Link to post
Share on other sites
Advertisement
You could use void gameGFX::write(int flags, long x, long y, int align, const char *fmt, const char *alt_fmt, bool useAlternate, ...) though I wouldn't recommend it. This seems like a violation of SRP. I'd personally stick with a non-vararg string output function and do formatting in a separate function.

Share this post


Link to post
Share on other sites
Is it possible to put a logical check in the parameter sending itself? So i can keep the original functions?

Something like:


bool ALT_LANG= true;
myfunc( if(ALT_LANG) "Foreign text %d" else "English text %d", x,y , width, variable, more stuff);


I have plenty of functions that take strings and would prefer to not make more versions of them all. So basically is there any way of writing two string parameters in the same "parameter slot" and then let some logic decide which one to send to the function?

Thanks a lot for your help
Erik

Share this post


Link to post
Share on other sites
Sure. Stick the if/else outside of the function call:

if(A)
myfunc(...); //parameter set 1
else
myfunc(...); //parameter set 2


Alternatively you could use the ternary operator:

myfunc( A ? "Hello World" : "Goodbye world");


The problem with either method is that it does not solve the ordering issue. Specifically, in one language A may come before B, whereas in another language B may come before A. A common example would be addressing someone by their full name in English versus Japanese. In english the given name comes first, followed by the surname. In japanese the surname comes first followed by the given name.

I'm with SiCrane though, the ellipses operator is a terrible thing to use in C++. boost::format (or similar) is a much better alternative, as it is type safe and quite flexible. Which also nicely handles the ordering problem. As an example:

std::string greetingString = "Hello %1% %2%";
if(nameOrdering == NameOrdering::SurNameFirst)
greetingString = "Hello %2% %1%";
write(boost::format(greetingString) % givenName % surName)

It's also generally a bad idea to hardcode display strings. A string table or similar keyed dataset is much more useful. It allows you to trivially centralize all of your localized information into a few locale specific files, instead of having the strings scattered throughout your source code. A sample implementation of that would look something like:


#include <boost/format.hpp>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <map>

namespace washu {
class locale_strings {
typedef std::map<std::string, std::string> strings_table;
strings_table strings_;
public:
locale_strings(std::string const& tableName) {
std::ifstream fin(tableName.c_str());
if(!fin) // If we were unable to open the strings file, throw exception.
throw std::runtime_error(boost::str(boost::format("Unable to open %1%.") % tableName));

while(fin) {
std::string line;
std::string key;
std::string value;

std::getline(fin, line); // read a line from the file
if(line.size() == 0 || line[0] == '#') // if the line is empty, or starts with a # then we skip over it.
continue; // this allows for comment lines.

std::istringstream iss(line); // format of the line is: keyname<SP>format text
iss >> key >> std::ws; // read out the keyname (one word) and the whitespace after it (seperator)
std::getline(iss, value); // read rest of the line into the value

strings_.insert(std::make_pair(key, value));
}
}

std::string const& get_string(std::string const& key) {
strings_table::const_iterator itor = strings_.find(key); // check to see if the key exists in the table
if(itor != strings_.end()) // found the key, so ...
return itor->second; // ... we return the value

throw std::runtime_error(str(boost::format("Unknown string key: %1%") % key)); // we didn't find the key, throw an exception.
}
};
}
int main() {
try {
washu::locale_strings strings = washu::locale_strings("strings.english");

std::cout<<boost::format(strings.get_string("greet")) % "Washu" % "Hakubi"<<std::endl;
} catch(std::exception& ex) {
std::cout<<ex.what()<<std::endl;
}
}

Share this post


Link to post
Share on other sites
im with you on the principal of the matter.
For this project i will go with the ? operator solution though, it will work good enough.

Thanks for the tip!
E

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.

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!