Bugzilla – Full Text Bug Listing |
Summary: | NS_LOG can not be used in templates | ||
---|---|---|---|
Product: | ns-3 | Reporter: | Tommaso Pecorella <tommaso.pecorella> |
Component: | core | Assignee: | Peter Barnes <pdbarnes> |
Status: | RESOLVED FIXED | ||
Severity: | enhancement | CC: | ns-bugs, stavallo, tomh |
Priority: | P1 | ||
Version: | ns-3-dev | ||
Hardware: | All | ||
OS: | All |
Description
Tommaso Pecorella
2017-03-08 18:55:18 EST
I haven't stared at the Queue<> design enough, so this may be gibberish: Isn't this the point of base classes, and QueueItem in particular? to give a minimal type for things like the things being Queued? So instead of template <typename Item> class Queue : public QueueBase { bool Enqueue (Ptr<Item> item); ... You do class Queue : public QueueBase { bool Enqueue (Ptr<QueueItem> item); ... Failing that, it seems the macro issue here has to do with emitting log messages from one compilation unit (which includes net-device-queue-interface.h, for example), but which really belong to the log component defined in another compilation unit, namely "NetDeviceQueueInterface" defined in net-device-queue-interface.cc. Perhaps we need static LogComponent & LogComponent::GetComponent (const std::string log); Then we can define logging macros like this: #define NS_LOG(log, level, msg) ... #define NS_LOG_DEBUG(msg) NS_LOG(g_log, ns3::LOG_DEBUG, msg) #define NS_LOG_DEBUG(log, msg) NS_LOG(LogComponent::GetComponent(log), ns3::LOG_DEBUG, msg) The second line will use the log component defined in the current compilation unit; the third line will use the designated log component. To define NS_LOG_DEBUG with either two or three args we would have to use the variadic macros tricks here: http://stackoverflow.com/questions/16683146 or define a new set of macros #define NS_LOG_DEBUG_COMP(log, msg) NS_LOG(LogComponent::GetComponent(log), ns3::LOG_DEBUG, msg) (In reply to Peter Barnes from comment #2) > Failing that, it seems the macro issue here has to do with emitting log > messages from one compilation unit (which includes > net-device-queue-interface.h, for example), but which really belong to the > log component defined in another compilation unit, namely > "NetDeviceQueueInterface" defined in net-device-queue-interface.cc. > > Perhaps we need > > static LogComponent & LogComponent::GetComponent (const std::string log); > > Then we can define logging macros like this: > #define NS_LOG(log, level, msg) ... > #define NS_LOG_DEBUG(msg) NS_LOG(g_log, ns3::LOG_DEBUG, msg) > #define NS_LOG_DEBUG(log, msg) NS_LOG(LogComponent::GetComponent(log), > ns3::LOG_DEBUG, msg) > > The second line will use the log component defined in the current > compilation unit; the third line will use the designated log component. > > To define NS_LOG_DEBUG with either two or three args we would have to use > the variadic macros tricks here: http://stackoverflow.com/questions/16683146 > > or define a new set of macros > #define NS_LOG_DEBUG_COMP(log, msg) NS_LOG(LogComponent::GetComponent(log), > ns3::LOG_DEBUG, msg) This is a very interesting solution, thanks! I will try to experiment with this approach as soon as I can. I elaborated Peter's suggestion a bit and implemented two approaches (only one is working atm...). Basically, we can reuse the classic NS_LOG_* macros if template classes define a LogComponent g_log member variable. The first (working) approach defines such member variables as non-static: https://codereview.appspot.com/320790043/ The second (non working) approach is an experiment I made to define the g_log member variables as static: https://codereview.appspot.com/319590043/ The issue here is the static initialization order (these member variables must be initialized to the log component defined in other compilation units). As a solution, I introduced an auxiliary object that creates a LogComponent the first time it is invoked and returns the created component the next times. However, all programs crash in a strange way: the LogComponent::IsEnabled method is called before any object of type LogComponent (or LogComponentRegistration) is constructed. Any opinion? Thanks! Hi, personally, I like enough option 1. I'll leave to Peter the final decision. Cheers, T. PS. we need also to document in the manual the slightly different use of the logging facilities for template / non-template classes. (In reply to Stefano Avallone from comment #4) > I elaborated Peter's suggestion a bit and implemented two approaches (only > one is working atm...). Basically, we can reuse the classic NS_LOG_* macros > if template classes define a LogComponent g_log member variable. The first > (working) approach defines such member variables as non-static: > > https://codereview.appspot.com/320790043/ > > The second (non working) approach is an experiment I made to define the > g_log member variables as static: > > https://codereview.appspot.com/319590043/ > > The issue here is the static initialization order (these member variables > must be initialized to the log component defined in other compilation > units). As a solution, I introduced an auxiliary object that creates a > LogComponent the first time it is invoked and returns the created component > the next times. However, all programs crash in a strange way: the > LogComponent::IsEnabled method is called before any object of type > LogComponent (or LogComponentRegistration) is constructed. > > Any opinion? Thanks! What about pushing option 1 so that it gets included in ns-3.27? (In reply to Stefano Avallone from comment #6) > What about pushing option 1 so that it gets included in ns-3.27? Can you implement changes that Peter suggests (macros, and documentation update) in the next few days? If so, we can include. I had a look at Peter's comments (thanks!), which I think are easy to address. I will provide a new patch by Monday. Pushed option 1 with changeset 12922:d5736db31887, thanks. |