Is there a way I can make a variable in C++ that has code inside of it that I can run later?
For example:
string code = "cout << "Hello World" << endl;"?
Or make a file or Notepad file that can be run later? Like if someone adds an employee to a program, it'll make a file and add all of the employee's information. Then later on when the program user says "I want to see that employee" by either writing their name or a unique ID, it shows all of the employee's information.
Thank you.
The solution is to use #define preprocessor directive to create a macro:-
#define code cout << "Hello World" << endl;
Now whereever you use the word 'code', it will be replaced by cout << "Hello World" << endl;
eg:
int main()
{
code
return 0;
}
Yes, it's relatively new syntax.
std::string msg = "Hello world";
auto code = [&std::cout, =msg]() {std::cout << msg;};
// Now we can pass code about as a variable.
code(); // runs it, even if std::cout and msg has gone out of scope
The advantage is that a comparison function, or a key access function, or similar can be attached to a bigger structure. You can also build entire programs out of lambdas, but that's getting rather theoretical.
However you must specify the C++ code at compile time. You can't compile C++ on the fly (yet).
Related
Edit 1: This is NOT a duplicate of this question because that person wants to know how to get the executable path. I can get the path just fine, I'm just wondering if there's a more convenient way of USING the path without modifying hundreds of calls to ifstream in my code.
Edit 2: First I'm moving Edit #1 to the top because people still think that the other question answers mine. It does not. I am NOT asking that question. Also I'm going to clarify that my initial question was probably phrased incorrectly. Someone posted in the comments a solution that works for me.
Here is how I would rephrase my question.
I have a program which spawns child processes, in other words it's a program that runs other programs. Program A spawns B, C, D, E, F, etc. My files are organized like so: Program A is at "dir/a/" and B is at "dir/a/b/" and C is at "dir/a/c/" etc.
Now assuming that Program B is written in C++ and it uses ifstream to deal with reading and writing files, my initial question was "is there a way to write Program B's code so that it can deal with reading in files from the executable directory and not from the directory it was spawned?" Because when A runs B, B thinks it's in "dir/a/" when the file is in "dir/a/b/file.txt". So calling ifstream("file.txt") goes to the wrong place. I would need to rewrite the code to ifstream(prefix + "file.txt") everywhere in Program B's code instead. This also needs to work such that I can run B directly rather than through A. Other programs like C, D, E, F, etc. may or may not be written in C++ and may or may not have implemented their own ways of handling this problem.
Many of the solutions posted are just different ways of doing the prefix + filename trick which I already knew about before I asked this question.
The solution posted below that I found which worked is to just change the directory before spawning the process. Thus when the process is spawned, it thinks it is in the new directory. This solves my problem because now it will work for any program, whether it is B, C, D, E, etc or whether it is in C++ or uses ifstream at all. This should have been really obvious in hindsight but for some reason I didn't realize I could run a command to change the directory before spawning the process. So this works for my case and so that's why it's the answer to my question.
Other people keep writing answers to the wrong question, though maybe that's my fault for not writing in the right way or understanding what my problem really was in the first place.
-- The original post --
I have two programs. Program A spawns the child process Program B. Program B uses std::ifstream("file.txt") to read in a file. However, Program A is located in /programs/a/ while Program B is in /programs/a/children/b/. Meaning that when I spawn B as a child process, Program B thinks its current directory is /programs/a and looks for file.txt there (but file.txt is actually in /programs/a/children/b).
I know that the first argument passed to Program B is always the executable path, so I can just take that and modify my calls to file I/O functions to prefix the path with that. But how do I do this in a good way? Is there a convenient way to get this to work without changing much code in Program B? I want to be able to run Program B on its own, as well as from Program A, and in both cases it should be able to read file.txt. That's why I can't just hardcode the filepath, I want it to work in both cases without changing any code between them.
For instance, I can think of making a wrapper class and then changing every call of std::ifstream so that it calls the wrapper instead, kind of like this:
std::ifstream Wrapper::ifstream(const std::string& path)
{
return std::ifstream(prefix + path); // prefix is member variable
}
But for a project with many calls to ifstream this is inconvenient and possibly inconsistent. Any accidental use of ifstream directly could cause a crash. I would also need to do the same thing for any output filestreams too. And I would really like to minimize any external dependencies, so I'd prefer if there was a built-in way to avoid this problem. It would be nice if I could just toggle some kind of option in the ifstream class so that any call to ifstream("file.txt") becomes ifstream("path/to/file.txt"). Is this the best I can do, or is there any better option out there?
There is a standard (since C++17) way to figure this out. It is important to notice that as this is standard, it should work with every platform where C++ is implemented: Windows, Linux, MacOS, etc. The standard will take care of handling idiosyncrasies as separators.
You can use std::filesystem::canonical to get the current executable's location. Then get the location of the parent directory and append the filename you want.
An example is:
namespace fs = std::filesystem;
int main( int argc, char* argv[] ) {
fs::path path( fs::canonical( argv[0] ) );
fs::path file = path.parent_path() / "file.txt";
std::cout << file << std::endl;
}
This should print /programs/a/children/b/file.txt on Linux or Mac and "c:\Programs\A\Children\b\file.txt" on Windows (if paths are like that).
Here is an illustration of using an environment variable as a common information that any program started from a shell in which it is defined can use. The writer writes a short text to a file, the reader reads it out. Both programs try to read the environment variable A_B_PROG_FILE which should contain the path to a file (which may not exist). This variable name is hard-coded common information; if we had the opportunity to use a common header (but not a duplicated one!) we could as well communicate the path itself that way; this is something to consider. But let's assume that the programs do not share a build environment.
First the writer.cpp:
#include <iostream>
#include <fstream>
#include <cstdlib>
/** #return -1 if file could not be opened, -2 if a write error occurred,
or 0 on success
*/
int main(int argc, char **argv)
{
const char *envPath = std::getenv("A_B_PROG_FILE");
const char *fpath = envPath ? envPath : "/tmp/defaultname.txt";
std::ofstream f(fpath);
if(!f)
{
std::cerr << "Couldn't open " << fpath << " for writing, exiting\n";
return -1;
}
f << "Hello, file ->" << fpath << "<- here!\n"
<< "This was written by ->" << (argc? argv[0] : "Unknown exe path") << "<-\n";
return f ? 0 : -2; // if f is not good exit with error code.
}
The reader is very similar:
#include <iostream>
#include <fstream>
#include <cstdlib> // getenv()
/** #return -1 if file could not be opened, -2 if a read error occurred,
or 0 on success
*/
int main()
{
const char *envPath = std::getenv("A_B_PROG_FILE");
const char *fpath = envPath ? envPath : "/tmp/defaultname.txt";
std::ifstream f(fpath);
if(!f)
{
std::cerr << "Couldn't open " << fpath << " for reading, exiting\n";
return -1;
}
std::cout << "file ->" << fpath << "<- contains: ->";
char c;
while(f.get(c))
{
std::cout << c;
}
std::cout << "<-";
if(!f.eof())
{
std::cerr << "Read error from ->" << fpath << "<-, exiting\n";
return -2;
}
}
Here is a sample session:
$ ls /tmp
$ unset A_B_PROG_FILE
$ ./reader
Couldn't open /tmp/defaultname.txt for reading, exiting
$ ./writer
$ ./reader
file ->/tmp/defaultname.txt<- contains: ->Hello, file ->/tmp/defaultname.txt<- here!
This was written by ->./writer<-
<-
$ export A_B_PROG_FILE=/tmp/ab
$ ./reader
Couldn't open /tmp/ab for reading, exiting
$ ./writer
$ ./reader
file ->/tmp/ab<- contains: ->Hello, file ->/tmp/ab<- here!
This was written by ->./writer<-
<-
$
I'm working on a simple game engine just for the experience of it. I've realized, though, that I have no idea how to export the user's custom game as its own standalone executable. For example (this is not my actual game engine, it just provides an easy reference for discussion), suppose we had the following very simple code:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
void RunGame(string question, string answer)
{
string submission;
cout << question << endl;
getline(cin, submission);
if (submission == answer)
cout << "Correct!";
else
cout << "Wrong!";
}
int main()
{
string question;
string answer;
cout << "Enter Question:" << endl;
getline(cin, question);
cout << "Enter Answer:" << endl;
getline(cin, answer);
RunGame(question, answer);
}
In this example the user gets to create their own customized bit of trivia, and then can test it immediately afterwards when RunGame is called. Now I want to be able to save their game with the trivia information they provided as its own .exe (basically it will perform from the call to RunGame onwards). How would I go about doing that?
To be clear, this isn't a question about what is the easiest/fastest way to make a game. It is looking for how to build a standalone, executable file from within code.
If you really want to store data inside the .exe itself:
An executable has a header that defines its size, boundaries and other useful stuff to the Operating System, so, essentially, the operating system knows where the code and data sections start and end, and it finally uses this information to load up the .exe to memory when it is asked to run.
Since the Operating System knows (besides the .exe's file size) where the executable actually ends, this also means that any data pasted after the .exe's "calculated" end (by headers) won't negatively effect the binary. It will still load and execute just fine.
You can abuse this property to concatenate data after the end of the executable.
I'll leave you with this test, using Windows' bundled WordPad application as a 'host' for some other data:
Go to C:\Windows and copy write.exe (WordPad) to another folder, so we can experiment without damaging anything.
Bring to that folder another file, any file will do. In my example, the data file will be a PDF called "myfancyfile.pdf"
Now, open a command prompt and use the COPY command to stitch both files together, making sure the .exe comes first:
copy /B write.exe+myfancyfile.pdf mynewprogram.exe
copy's /B flag means "binary copy", so essentially both files were pasted together without any kind of text or data conversion.
Try to run "mynewprogram.exe". Realize it runs just fine :-)
Self-modifying your .exe with data is not only feasible, it won't negatively effect functionality. Having that said, it is still a ugly way to persist data.
Have fun coding your solution.
You don't want to do this. A better way is to save the trivia in some custom format (for example, .txt, .dat, ..).
Then the game just handles this data.
So first think about the format inside of the .txt for example.
Lets say at first theres a number, indicating which entry this is. Second follows the question and after that the answer follows. This, you must decide for yourself.
Example trivia-data.txt
1
How old is actor X from show Y?
32 years
2
...
...
#include <iostream> // std::cout, std::endl
#include <fstream> // std::ifstream, std::ofstream
using namespace std;
int main()
{
// create file
ofstream ofile("trivia-data.txt");
// define your data
int num_of_question = 1;
string question, answer;
getline(cin, question);
getline(cin, answer);
// write your data to the file
ofile << num_of_question << '\n';
ofile << question << '\n';
ofile << answer << '\n';
// close the file
ofile.close();
return 0;
}
Now that you created your data you just have to build your program in a way you would like to present this. Instead of writing to a file, you should read from a file and print the questions out and compare answers and what not. Look up std::ifstream for reading your file.
At the start you could ask your user if he would like to create a quiz or play one that already exists.
Edit:
Since this sounds a lot like homework I just provide some pseudo code.
I'd go for an approach like this(pseudo code):
print "Would you like to create(c) or play(p) a quiz? Answer(c/p): "
input = get_input() // 'c' or 'p'
if input == 'c'
// now do what I posted with some loops to create a couple of questions
else
print "Please provide an URL to the quiz-data you would like to play: "
url = get_input() // C:/test.txt
// read in data, print out questions, do comparisons and print answers etc
This is infinitely easier than your approach and this also makes it possible for others to create quizzes not just you.
Building an executable is non-trivial. You will first need to comply with the target operating systems' ABI so that it can find your program's entry point. The next step will be deciding how your program is going to be able to access system resources: probably you'll want your executable to implement dynamic linking so it can access shared libraries, and you'll need to load the various .dll or .so files you're going to need. All the instructions you'll need to write for this will vary from OS to OS, you may need to introduce logic to detect the exact platform and make informed decisions, and you will need to vary for 32 vs 64 bit.
At this point you're about ready to start emitting the machine instructions for your game.
A reasonable alternative here is (as done by Unity) to provide a "blank" executable with your engine. Your engine itself would be a shared library (.dll or .so) and the blank executable would simply be a wrapper that loads the shared library and invokes a function in it with a pointer to something in it's data section.
Generating your user's executable would comprise loading the appropriate blank, making platform-specific modifications to it to tell it the size of the data section you're intended to provide it with and writing your data in the appropriate format. Or, you could simply have a blank that has an embedded copy of the raw structure into which you write values, just like populating a struct in memory:
struct GameDefinition {
constexpr size_t AuthorNameLen = 80;
char author_[AutherNameLen+1];
constexpr size_t PublisherNameLen = 80;
char publisher_[PublisherNameLen+1];
constexpr size_t GameNameLen = 80;
char name_[GameNameLen+1];
constexpr size_t QuestionLen = 80;
constexpr size_t AnswerLen = 80;
char question_[QuestionLen+1];
char answer_[AnswerLen+1];
};
static GameDefinition gameDef;
#include "engine_library.h" // for run_engine
int main() {
run_engine(&gameDef);
}
You'd compile this againsst the shared-library stub for your engine, and emit it as an executable, then you'd look up the platform-specific details of the executable format, locate the position of "gameDef" in it. The you'd read the blank into memory, and write it out with the definition of "gameDef" replaced with the one based on user input.
But what many engines do is simply ship or require the user to install a compiler (Unity relies on C#). So instead of having to tweak executables and do all this crazy platform-specific stuff, they simply output a C/C++ program and compile it.
// game-generator
bool make_game(std::string filename, std::string q, std::string a) {
std::ostream cpp(filename + ".cpp");
if (!cpp.is_open()) {
std::cerr << "open failed\n";
return false;
}
cpp << "#include <engine.h>\n";
cpp << "Gamedef gd(\"" << gameName << "\", \"" << authorName << \");\n";
cpp << "int main() {\n";
cpp << " gd.q = \"" << q << \"\n";
cpp << " gd.a = \"" << a << \"\n";
cpp << " RunGame(gd);\n";
cpp << "}\n";
cpp.close();
if (!invoke_compiler(filename, ".cpp")) {
std::cerr << "compile failed\n";
return false;
}
if (!invoke_linker(filename)) {
std::cerr << "link failed\n";
return false;
}
}
If "RunGame" is not part of your engine but user-supplied, then you could emit that as part of the cpp code. Otherwise, the intent here is that it's making a call into your library.
Under Linux you might compile this with
g++ -Wall -O3 -o ${filename}.o ${filename}.cpp
and then
g++ -Wall -O3 -o ${filename} ${filename}.o -lengine_library
to link it against your engine's library.
When you stream variables to an output stream such as cout, type conversion is automatic. What I'm trying to figure out is how to do this via a function call, for example:
inline void DEBUG(ostream& s) // Don't know if this prototype is appropriate
{
cout << s;
}
main()
{
int i = 5;
DEBUG("The value is: " << i << endl); // This doesn't compile
DEBUG("The value is: " + i + endl); // Neither does this
}
I found similar questions on here, but they all involve passing the stream object as a parameter, whereas I'm trying to pass the "streamed data" to a function that already has the stream object, so it's the other way round. Is this even possible? I don't want to resort to explicit type conversions. I also found this question, but I really don't want to write a whole logger class if I can avoid it.
At the moment I'm implementing it as a macro, which works, but I'd rather use an inline function if possible.
#define DEBUG(s) (cout << s)
Of course it does not compile. There are many reasons for that.
First, Operator << is not defined for standard streams, and you are trying to do exactly that: stream stream into stream in your DEBUG(). (Pun intended).
Second, operator << is not defined for string literals, and you are trying to invoke it here:
"The value is: " << i
+ is not defined for literals either, by the way.
To achieve the semantic you want to see, you will have to start with the stream. String literal need to be converted to stream first, and than you can apply << to it. This is ONLY way to achieve what you want.
Edit:
Now since I understand the rationale, I can give a better answer. There are many ways how people are trying to segregate different levels of debugging uniformely, and there are several libraries aiming for that (log4cpp, boost.log to name just few). Before you start implementing your own logging, I would definitely suggest looking into those. There is much more to the good logging than just debug levels.
If, for any reason, you want to use your own homebrew, here are the couple of recepies you might explore:
Use your own logger class (one of the very rare examples, close to
the single one! where Singleton is appropriate). You can than set the
logging level in the beggining of your application, and than just
call Logger::debug() << ...
Enrich above solution with macros. The problem with functions is that, unlike macros, they loose context. So if you want to log file and line number of the logging invocation (and you usually do!), you might want to do LOG_DEBUG << ...; here LOG_DEBUG would expand into something like Logger::debug() << __FILE__ << ":" << __LINE__ << ....
Once you've done this, you will see that sometimes you call other functions inside the << chain. At this point you might realize that those functions would be called regardless of your debug level, and might think you do not want to call them when debugging is not enabled (something along the lines LOG_DEBUG << " Object now is " << object.serialize(); So you will want to enrich the LOG_DEBUG macro to not execute anything when debug level does not match.
And the saga continues... Ready to use the library?
Well, what (at least some) logging libraries would do is create a temporary proxy object that would act as a stream:
#include <iostream>
struct LoggerProxy {
LoggerProxy(const char* file, int line)
{
std::cout << "File " << file << ", line " << line << ": ";
}
template<typename T>
LoggerProxy& operator<<(T&& t)
{
std::cout << t;
return *this;
}
};
#define LOG_DEBUG LoggerProxy{__FILE__, __LINE__}
int main()
{
LOG_DEBUG << "Value is: " << 4;
}
You can do a lot of fancy stuff with this, such as debug level checks, output to different streams or multiple backends (such as simultaneous output to std::cout/cerr and log file) and many more.
I am looking for a clever way to track function calls and returns.
I know I can use the debugger, but I would like a way to just have it print something out to the terminal when calling a function vs having to step through code.
I am thinking that I might be able to use the preprocessor, but I am not sure what would be the best way to go about this.
Or is there a way to use gdb to print out the information that would be useful, while not having to step through the code.
Most compilers allow you to inject an instrumentation function before and after the function call.
In MSVC they are _penter and _pexit. A nice article: http://www.drdobbs.com/184403601.
In GCC you would use the -finstrument-functions option, see the docs.
You can use debug libaries or map files to get more info.
A quite intrussive solution is using RAII to control the scope of the function. This will have a great impact in performance, but will be quite explicit in the logs without requiring the user to add instrumentation in all possible code paths that may leave the function:
class ScopeLogger {
public:
ScopeLogger( std::string const & msg ) : msg(msg)
{ std::cout << "Enter: " << msg << std::endl; }
~ScopeLogger()
{ std::cout << "Exit: " << msg << std::endl; }
std::string msg;
};
#if DEBUG
#define FUNCTION(x) ScopeLogger l_##x##_scope(x);
#endif
void foo( int value ) {
FUNCTION( __FUNCTION__ );
if ( value > 10 ) throw std::exception;
std::cout << "." << std::endl;
}
int main() {
foo(0); // Enter: foo\n.\nExit: foo
foo(100); // Enter: foo\nExit: foo
}
If the code is single threaded, you might even want to add a static variable with some indentation level to ScopedLogger without adding too much to the already heavy performance impact:
class ScopeLogger {
public:
ScopeLogger( std::string const & msg ) : msg(msg)
{ std::cout << std::string(indent++,' ') << "Enter: " << msg << std::endl; }
~ScopeLogger()
{ std::cout << std::string(--indent,' ') << "Exit: " << msg << std::endl; }
std::string msg;
static int indent;
};
int ScopeLogger::indent = 0;
Since you are using GCC, you can also use linker function wrapping.
Link-Time Replacement / Wrapping
– GCC option: -Wl,--wrap,function_name
Basically, you can take a function called "function_name()" and wrap it with a function called "__wrap_function_name()". You can access the original function by calling "__real_function_name()".
#define BEGIN_FUNC(X) printf("Function %s Entered",X)
#define END_FUNC(X) printf("Function %s End",X)
foo()
{
BEGIN_FUNC(__func__);
//Your code here
END_FUNC(__func__);
}
I think if you write a macro like above and use it for every function as described then you can get the logs on the terminal.
You may want to look at Valgrind's Callgrind which can track function calls into a pretty graph. It will show function calls, but not the parameter or return values.
Or is there a way to use gdb to print out the information that would be useful, while not having to step through the code
Yes. Set a breakpoint only at the functions that you actually care about. Use "continue" until you get to those functions or until your program crashes. Then use "backtrace" (or "bt") to get a stack trace.
If you need to automate it, you might take a look at TARGET_ASM_FUNCTION_END_PROLOGUE and TARGET_ASM_FUNCTION_BEGIN_EPILOGUE. These are compiler hooks that will let you specify pieces of assembly to be emitted along with the normal function prologue/epilogue -- in your case, you'd use them to emit a little assembly to log the entry/exit from the function in question. You could also look at FUNCTION_PROFILE and/or PROFILE_HOOK (e.g., at: http://gcc.gnu.org/onlinedocs/gccint/Function-Entry.html).
Below is an example illustrating the GCC side of the answer by Jonathan Fischoff.
Here we call external tool addr2line to print the location as functionName at /path/to/file.cpp:line instead of simply the address. I've tried using dladdr for this (as suggested in a comment to the answer linked above), but it returned only null pointers in dli_sname for me.
This approach of resolving the addresses has some drawbacks:
It's slow due to fork/execve/file read.
It needs exact file path to the binary containing the address, so the simple code below can't print symbols in shared libraries.
// Instrumentation
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void __attribute__((no_instrument_function))
log_func(const void* funcAddr, const char* action, const void* callSite)
{
char cmd[50];
snprintf(cmd, sizeof cmd, "addr2line -Cpfe /proc/%d/exe %p", getpid(), funcAddr);
fprintf(stderr, "%p %s %p ", callSite, action, funcAddr);
system(cmd);
}
extern "C" void __attribute__((no_instrument_function))
__cyg_profile_func_enter(void* this_fn, void* call_site)
{
log_func(this_fn, "->", call_site);
}
extern "C" void __attribute__((no_instrument_function))
__cyg_profile_func_exit(void* this_fn, void* call_site)
{
log_func(this_fn, "<-", call_site);
}
// Actual code we're tracing
#include <iostream>
struct Test
{
Test() { std::cout << "Hi, I'm Test constructor\n"; }
void method() const { std::cout << "And I'm Test method\n"; }
};
int main()
{
std::cout << "Hello, my name is main\n";
Test test;
test.method();
}
Compilation and running:
$ g++ test.cpp -o test -g -finstrument-functions && time ./test
0x8048b0b -> 0x804899b _GLOBAL__sub_I___cyg_profile_func_enter at /tmp/test.cpp:41
0x80489c4 -> 0x804890b __static_initialization_and_destruction_0(int, int) at /tmp/test.cpp:41
0x80489c4 <- 0x804890b __static_initialization_and_destruction_0(int, int) at /tmp/test.cpp:41
0x8048b0b <- 0x804899b _GLOBAL__sub_I___cyg_profile_func_enter at /tmp/test.cpp:41
0xf7a0de71 -> 0x804886a main at /tmp/test.cpp:37
Hello, my name is main
0x80488b1 -> 0x80489de Test::Test() at /tmp/test.cpp:32
Hi, I'm Test constructor
0x80488b1 <- 0x80489de Test::Test() at /tmp/test.cpp:32
0x80488c0 -> 0x8048a4a Test::method() const at /tmp/test.cpp:33
And I'm Test method
0x80488c0 <- 0x8048a4a Test::method() const at /tmp/test.cpp:33
0xf7a0de71 <- 0x804886a main at /tmp/test.cpp:37
real 0m0.062s
user 0m0.054s
sys 0m0.008s
There is a __FUNCTION__ (Reference) macro used to determine what method (in the format Class::Method) you're in, but this is more of a manual process.
However, when I needed the same 'trace' information recently, I could not find a automatic method.
I would like to have an easy to use way to write code like:
#include <iostream>
int main (){
std::cout << "hello, world!\n";
}
but that supports i18n. Here is an example using gettext():
#include <libintl.h>
#include <iostream>
int main (){
std::cout << gettext("hello, world!\n");
}
This can then be processed by xgettext to produce a message catalog file that can be used
by translators to create various versions. These extra files can be handled on target
systems to allow the user to interact in a preferred language.
I would like to write the code something like this instead:
#include <i18n-iostream>
int main (){
i18n::cout << "hello, world!\n";
}
At build time the quoted strings would be examined by a program like xgettext to produce the
base message catalog file. << operator with argument i18n::cout would take a string
literal as the key to lookup the run-time text to use from a message catalog.
Does it exist somewhere?
At build time the quoted strings would be examined by a program like xgettext to produce the base message catalog file. << operator with argument i18n::cout would take a string literal as the key to lookup the run-time text to use from a message catalog.
You try to convert a string like a single instance, but it isn't/
The point, you don't want something like this. Think of:
if(n=1)
i18n::cout << "I need one apple"
else
i18n::cout << "I need " << n << " apples" ;
So why this is would not work, because "n=1" or "n!=1" works only for English, many other languages have more then one plural form, also it requires translation of "I need X apples" as signle instance.
I suggest you just to learn to deal with gettext, it is quite simple and powerful, many people had thought about it.
Another point, you are usually do not call gettext but
#include <libintl.h>
#include <iostream>
#define _(x) gettext(x)
int main (){
std::cout << _("hello, world!\n");
}
This makes the code much cleaner, also it is quite a "standard" feature to use "_" as gettext alias.
Just learn how to use it, before you try to make "nicer" API. Just to mention, gettext API is quite de-facto standard for many languages, not only C.
The short answer is "No" :)
Seriously, which aspects of internationalization are you interested in? ICU provides pretty much everything but does not feel like standard C++. There are other libraries smaller in scope that provide some i18n functionalities, i.e. UTF-CPP for handling UTF-8 encoded strings.
Personally I would go with this answer, but it might be possible to use a bit of streambuf magic to do this as the text is written to the stream. If you're really interested in doing this though, please take a look at Standard C++ IOStreams and Locales by Langer and Kreft, it's the bible of iostreams.
The following assumes that everything written to the buffer is to be translated, and that each full line can be translated completely:
std::string xgettext (std::string const & s)
{
return s;
}
The following transbuf class overrides the "overflow" function and
translates the buffer every time it sees a newline.
class transbuf : public std::streambuf {
public:
transbuf (std::streambuf * realsb) : std::streambuf (), m_realsb (realsb)
, m_buf () {}
~transbuf () {
// ... flush m_buf if necessary
}
virtual std::streambuf::int_type overflow (std::streambuf::int_type c) {
m_buf.push_back (c);
if (c == '\n') {
// We have a complete line, translate it and write it to our stream:
std::string transtext = xgettext (m_buf);
for (std::string::const_iterator i = transtext.begin ()
; i != transtext.end ()
; ++i) {
m_realsb->sputc (*i);
// ... check that overflow returned the correct value...
}
m_buf = "";
}
return c;
}
std::streambuf * get () { return m_realsb; }
// data
private:
std::streambuf * m_realsb;
std::string m_buf;
};
And here's an example of how that might be used:
int main ()
{
transbuf * buf = new transbuf (std::cout.rdbuf ());
std::ostream trans (buf);
trans << "Hello"; // Added to m_buf
trans << " World"; // Added to m_buf
trans << "\n"; // Causes m_buf to be written
trans << "Added to buffer\neach new line causes\n"
"the string to be translated\nand written" << std::endl;
delete buf;
}
You mean you just want another API? You could write a small wrapper, shouldn't be too hard and it would give you the possibility to use the best API you can think of :)