I am trying to write a macro to expand the contents of a struct:
struct Str
{
int a;
float f;
char *c;
};
Str s = {123, 456.789f, "AString"};
#define STRINGIFY_STR(x) ... // Macro to stringify x which is an instance of Str
printf("%s", STRINGIFY_STR(s));
desired output: [a: 123, f:456.789, c:AString]
Is it possible to write a macro that does this? If it is, then how?
Is there a reason you want to do this as a macro?
You should write a function to perform this action instead of using the preprocessor.
Depending on your goals, there are a few options. The boost formatting library provides a great toolkit to build the formatted string. You could always overload operator<<
to provide clean output, as well.
If you're doing this in pure C, the sprintf family of methods work for creating formatted output.
This is quite gross, and only works on gcc
/g++
.
#define STRINGIFY_STR(x) \
std::string(({ std::ostringstream ss; \
ss << "[a: " << x.a \
<< ", f: " << x.f \
<< ", c: " << x.c << "]"; \
ss.str(); })).c_str()
You have to create the string from the values. Please don't do it this way. Please follow Reed's advice.
Here is how I would modify your struct
to allow it to be pretty printed:
struct Str
{
int a;
float f;
char *c;
std::ostream & dump (std::ostream &os) const {
return os << "[a: " << a
<< ", f: " << f
<< ", c: " << c << "]";
}
};
std::ostream & operator << (std::ostream &os, const Str &s) {
return s.dump(os);
}
Str s = {123, 456.789f, "AString"};
Now, to print out s
, you can use std::cout
:
std::cout << s << std::endl;
Or, if you really want a string:
std::stringstream ss;
s.dump(ss);
puts(ss.str().c_str());
struct stringify
{
operator std::string() const
{
return str ;
}
std::string str ;
};
template < typename T > stringify operator+ ( stringify s, const T& object )
{
std::ostringstream stm ;
stm << object ;
if( !s.str.empty() && !std::isspace( *s.str.rbegin() ) ) s.str += ' ' ;
s.str += stm.str() ;
return s ;
}
I'm also against the approach, but to answer the question:
#define STRINGIFY_STR(x) \
(std::string("[a: ") + std::to_string((long double)x.a) \
+ std::string(", f:") + std::to_string((long double)x.f) \
+ std::string(",c: ") + x.c + std::string("]") ).c_str()
I suggest writing a member function that does this though.