I am trying to modify my log class to accept variab开发者_StackOverflow社区les in my string. For example, if I wanted to output that there are 7 players in an area.
Here is my write to log function:
void Log::writeSuccess(string text,...)
{
// Write the sucessfull operation to the logfile
logfile << "<---> " << text << endl;
}
And here is my calling code:
int playernum = 7;
errorLog.writeSuccess("There are %i players in the area", playernum);
It just ends up outputting to the file: There are %i players in the area
Any way to fix this?
I wonder how on earth does your program even compile?!
You call writeSuccess
with 2 arguments, whereas it is declared to take only one argument.
You should look at boost format
The problem with using printf
-style format strings is that those strings are
- dependent on the types of the provided arguments, and
- dependent on the order of the provided arguments.
Not only is this error-prone when you are writing those lines. In my experience the types and order of the arguments will easily change in software that is actively maintained and extended, and it's much harder still to keep the format strings in sync with changes applied later, than it is to do so when you initially write the code.
The problem of needing to manually keep the parameter types in sync with the format string can easily be solved in C++, streams have proven that 25 years ago. Boost.Format even manages to combine format strings with type safety.
A different approach, solving both problems, is taken by some logging libraries I have seen: They use a syntax where you specify which parameter is to be inserted at a specific place in a string by using the parameter's name, and they free you from having to think about the parameter's type by individually converting all parameters to strings before inserting them:
log( "i now has the value of @(i), current size is @(x.get_size(y))",
LOG_PARAM(i) + LOG_PARAM(x.get_size(y)) );
If you don't want to use stdarg.h which doesn't look good in c++ IMO. you can do something like this. Keep in mind that although this is a small class (you can add to it for better logging), its not the most efficient way to do it.
#include <iostream>
#include <sstream>
class Log
{
public:
Log() : os()
{
}
~Log()
{
fprintf(stderr, "%s\n", os.str().c_str());
}
template<typename T>
std::ostringstream &operator<<(const T &t)
{
os << "Log file - " << t;
return os;
}
private:
std::ostringstream os;
};
int main(int argc, char *argv[])
{
//usage
for (int i = 0; i < 10; ++i)
Log() << "Hello world " << i;
return 0;
}
Look at stdarg standard library. It allows you to handle variable number of parameters.
In case you can't or won't use boost:
void Log::writeSuccess(const char* const fmt, ...) {
va_list ap;
va_start(ap, fmt);
char buff[1024];
vsnprintf(buff, sizeof(buff), fmt, ap);
logfile << buff;
}
Note: it assumes that the written length is limited.
Update: with gcc it's possible to do this in a type-safe way, you need the following declaration.
class Log {
void writeSuccess(const char* const fmt, ...) __attribute__ ((format (printf, 2, 3)));
//...
};
Info here. Note: it's a warning, not a compile error. If you ignore warnings that's your problem..:)
精彩评论