问题
In my code, I have repeatedly this expression:
T foo;
do_sth(foo, "foo");
I am considering stringifying the variable name, like this:
#define VARNAME(Var) (#Var)
void do_sth_new(T foo) { do_sth(foo, VARNAME(foo)); };
T foo;
do_sth_new(foo);
Is it good practice? Is there any better alternative in C++11?
回答1:
As you show it, it doesn't work since VARNAME(foo)
will always be "foo"
(as this is the parameter's name). You have to write do_sth_new
itself as macro:
#define do_sth_new(_foo) \
do { do_sth(_foo, #_foo); } while (false)
Only then will this:
T bar;
do_sth_new(bar);
generate "bar"
.
And no, there is no alternative to using the preprocessor since this is an operation on the lexical level. You'd need LISP-level modification of the AST in the language to have a better solution, which is unlikely to ever happen.
回答2:
Sadly, no. There is still no solution (not even in C++17) to this problem. There might be something once static reflection will be added to C++. But for the time being you're stuck with the macro.
回答3:
There is no real way to avoid the macro to do the stringify.
What you can do is dress it in a more c++ object-oriented way, especially if you want to do multiple different methods that take an object and its var name, and if this is a debug feature you might want to disable in production.
So I'm proposing you declare a template class DebugContextWrap, and objects of this type (or const ref) can be passed into the function as a single parameter, instead of having 2 parameters.
The one downside is that where your function code actually wants to access the actual value then you would have to perform an indirection through operator ->
or data()
as you do for iterators.
You could then write a macro that generates instances of DebugContextWrap - something like:
template class FooType
class DebugContextWrap
{
FooType& fooVal;
const char* debugName;
const char* debug__FILE__val;
const int debug__LINE__val;
public:
DebugContextWrap(FooType& fooVal,
const char* debugName, const char* debug__FILE__val, const int debug__LINE__val)
{ ... }
DebugContextWrap(FooType& fooVal) // implicit when caller doesn't use DEBUG_WRAP
{ ... }
FooType* operator ->()const
{ return &foo; }
FooType& operator *()const
{ return foo; }
FooType& Data()const
{ return foo; }
const char* DebugName()const
{ return debugName; }
};
#define DEBUG_WRAP(foo) \
DebugContextWrap<decltype foo>(foo, #foo, __FILE__, __LINE__)
void do_sth(const DebugContextWrap<FooType>& foo);
do_sth(DEBUG_WRAP(foovar));
来源:https://stackoverflow.com/questions/59660682/alternatives-to-stringifying-the-variable-name-in-c11