I am creating a logging facility for my library, and have made some nice macros such as:
#define DEBUG myDebuggingClass(__FILE__, __FUNCTION__, __LINE__)
#define WARING myWarningClass(__FILE__, __FUNCTION__, __LINE__)
where myDebuggingClass and myWarningClass both have an overloaded << operator, and do some helpful things with log messages.
Now, I have some base class that users will be overloading called "Widget", and I would like to change these definitions to something more like:
#define DEBUG myDebuggingClass(__FILE__, __FUNCTION__, __LINE__, this)
#define WARNING myWarn开发者_运维技巧ingClass(__FILE__, __FUNCTION__, __LINE__, this)
so that when users call 'DEBUG << "Some Message"; ' I can check to see if the "this" argument dynamic_casts to a Widget, and if so I can do some useful things with that information, and if not then I can just ignore it. The only problem is that I would like users to be able to also issue DEBUG and WARNING messages from non-member functions, such as main(). However, given this simple macro, users will just get a compilation error because "this" will not be defined outside of class member functions.
The easiest solution is to just define separate WIDGET_DEBUG, WIDGET_WARNING, PLAIN_DEBUG, and PLAIN_WARNING macros and to document the differences to the users, but it would be really cool if there were a way to get around this. Has anyone seen any tricks for doing this sort of thing?
Declare a global Widget* const widget_this = NULL;
and a protected member variable widget_this
in the Widget class, initialized to this
, and do
#define DEBUG myDebuggingClass(__FILE__, __FUNCTION__, __LINE__, widget_this)
Macros are basically a straight text substitution done by the preprocessor. There's no way for a macro to know the context from which it's being called to do the sort of detection you're interested in.
The best solution is probably separate macros as you suspect.
I don't think you can do this with a macro. You can probably manage to do it with SFINAE, but code that uses SFINAE (at least directly) is1 hard to write, harder to debug, and virtually impossible for anybody but an expert to read or understand. If you really want to do this, I'd try to see if you can get Boost enable_if
(or a relative thereof) to handle at least part of the dirty work.
1 ...at least in every case I've ever seen, and I have a hard time imagining it being otherwise either.
Inspired by solipist, but slightly simpler in the implementation:
class Widget {
protected:
::myDebuggingClass myDebuggingClass(char const* file, char const* function, int line) {
return ::myDebuggingClass(file, function, line, this);
}
// ...
This eliminates the need for a shadowed variable; it relies on simple class name lookup rules.
The only way I can think of to possibly get this to work is to define a global variable:
Widget * this = NULL;
If that even compiles (I have my doubts, but don't have a compiler to test it), member functions will use the nearest scoped variable (the real his
pointer), and everything else will get a null. Everyone's happy (so to speak...)
you could use weak reference to detect variable or function whether exist. eg: detect int a exist:
int a attribute((weak)); if (a) exist else not exist
精彩评论