I am trying to write a macro for logging mechanism. I wrote a variadic macro but it does not work with std::string
. The code looks like the following:
#include <stdio.h>
#include <string>
#define LOG_NOTE(m, ...) printf(m, ##__VA_ARGS__)
int main()
{
std::string foo = "random string";
int bar = 5;
LOG_NOTE("%s %d %s", "Hello World", bar, foo);
return 0;
}
If I would call the macro like following, I would not get any error.
LOG_NOTE("%s %d %s", "Hello World", bar, "random string");
Compiler Output:
In function 'int main()': 5:49: error: cannot pass objects of non-trivially-copyable type 'std::string {aka class std::basic_string}' through '...' 11:5: note: in expansion of macro 'LOG_NOTE'
I wrote a variadic macro
Don't. Use a variadic template function.
The actual problem you have is that you're trying to pass a C++ object (std::string
) through a C API (printf
). This is not possible.
You'd need some mechanism for conversion, for example:
#include <stdio.h>
#include <string>
template<class T>
decltype(auto) convert_for_log_note(T const& x)
{
return x;
}
decltype(auto) convert_for_log_note(std::string const& x)
{
return x.c_str();
}
template<class...Args>
void LOG_NOTE(const char* format, Args&&...args)
{
printf(format, convert_for_log_note(args)...);
}
int main()
{
std::string foo = "random string";
int bar = 5;
LOG_NOTE("%s %d %s\n", "Hello World", bar, foo);
return 0;
}
Example output:
Hello World 5 random string
http://coliru.stacked-crooked.com/a/beb3431114833860
Update:
For C++11 you'll need to spell out the return types by hand:
#include <stdio.h>
#include <string>
template<class T>
T const& convert_for_log_note(T const& x)
{
return x;
}
const char* convert_for_log_note(std::string const& x)
{
return x.c_str();
}
template<class...Args>
void LOG_NOTE(const char* format, Args&&...args)
{
printf(format, convert_for_log_note(args)...);
}
int main()
{
std::string foo = "random string";
int bar = 5;
LOG_NOTE("%s %d %s\n", "Hello World", bar, foo);
return 0;
}