Falling back to printf
function family and format strings brings you back quite a lot of issues concerning type safety You might be better off with modern C++ streaming mechanism. Sure, one wouldn't really want to log like this:
logger << "first: " << x << "second: " << y << commit;
So coming up with some alternative approach avoiding the problem with need for appropriate format string parameters; idea is the following:
- arguments are inserted one after another at designated locations in the format string
- insertion locations are identified by the character pattern
%#
- pattern
%##
suppresses argument insertion and is replaced with the insertion pattern as string
Disadvantage: we have to do the parsing ourselves:
void logInfo(char const* message)
{
char const* m = message;
while((m = strchr(m, '%')))
{
if(*++m == '#')
{
if(*++m != '#')
{
std::cout.write(message, m - message - 2);
std::cout << "<missing argument>";
}
else
{
std::cout.write(message, m - message);
++m;
}
message = m;
}
}
std::cout << message << std::endl;
}
template<typename A, typename ... AA>
void logInfo(char const* message, A a, AA ... aa)
{
char const* m = message;
while((m = strchr(m, '%')))
{
if(*++m == '#')
{
if(*++m != '#')
{
std::cout.write(message, m - message - 2);
std::cout << a;
return logInfo(m, aa...);
}
std::cout.write(message, m - message);
message = ++m;
}
}
std::cout << message << std::endl;
}
Sure, there is quite some common code yet, leaving to you to optimise, it's just for the idea...
Worked fine with the following examples:
logInfo("t1");
logInfo("t2", 7);
logInfo("t3: %#", 12);
logInfo("t4: %#%##", 10);
logInfo("t5: %#%%#", 12);
logInfo("t6: %#% baz", 10);
logInfo("t7 1: %# 2: %# 3: %#", 10, 12);
You might add further formatting options such as minimal output width, fill characters, precision, ... – just as printf provides as well...
Sure, this answer does not match exactly your question ("how to produce a warning"), instead, it simply makes the warning obsolete...