Is there anyway to write the following as a C++ ma

2019-01-10 23:22发布

my_macro << 1 << "hello world" << blah->getValue() << std::endl;

should expand into:

std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());

7条回答
狗以群分
2楼-- · 2019-01-10 23:55

Take a look at google-glog, they do this using a temporary object instanciated with a

LOG(INFO) << "log whatever" << 1;

and they also have other interesting macros such as LOG_IF et al.

查看更多
Ridiculous、
3楼-- · 2019-01-11 00:06

Considering you have these lines included somewhere in your code, yes it is possible

#include <iostream>
#include <sstream> 

__LINE__ macro is defined by all standart compilers. So we can use it to generate a variable name wich is different each time you use the macro :)

Here is a new version that is seen as a one-statement instruction only: (EDITED)

#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
     Var(s, __LINE__).x<2; ++Var(s, __LINE__).x)  \
    if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
    else Var(s, __LINE__).oss

// So you can use it like this 
int main() 
{ 
    if (4 != 2)
        my_macro << 4 << " hello "  << std::endl; 
    my_macro << 2 << " world !" << std::endl; 
} 

Developper probably won't need to use this macro twice on same line becasue of simplicity of operator <<. But in case you need this, you can switch the use of __LINE__ by __COUNTER__ (which is non standard!). Thanks to Quuxplusone for this tip

查看更多
Juvenile、少年°
4楼-- · 2019-01-11 00:08

The logging setup I have is quite similar:

bool ShouldLog(const char* file, size_t line, Priority prio);

class LoggerOutput : public std::stringstream {
public:
  LoggerOutput(const char* file, size_t line, Priority prio) 
  : prio(prio) 
  {
    Prefix(file, line, prio);
  }
  void Prefix(const char* file, size_t line, Priority prio);
  ~LoggerOutput() {
    Flush();
  }
  void Flush();
private:
  Priority prio;
};

#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)

If your logging is disabled, the ostream is never created and little overhead exists. You can configure logging on file name & line number(s) or priority levels. The ShouldLog function can change between invocations, so you could throttle or limit output. The log output uses two functions to modify itself, Prefix that adds a "file:line: (PRIO) " prefix to the line, and Flush() which both flushes it to the log output as a single command and adds a newline to it. In my implementation it always does, but you can make that conditional if one is not already there.

查看更多
Bombasti
5楼-- · 2019-01-11 00:09

Couldn't you just derive from ostream and provide your own thread safe implementation? Then you could just do

myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;

And get the exact same functionality without macros and using C++ properly?

查看更多
smile是对你的礼貌
6楼-- · 2019-01-11 00:11

No. The problem is that without using function syntax, a macro is limited to only being replaced where it is.

But if you were willing to use function syntax, you can then replace stuff both before and after the args.

my_macro(1 << "hello world" << blah->getValue() << std::endl);

You could by defining MyMacro as:

#define my_macro(args) std::ostreamstring oss; \
                       oss << args; \
                       ThreadSafeLogging(oss.str());
查看更多
We Are One
7楼-- · 2019-01-11 00:13

Here's another nasty trick I saw somewhere else. It has a significant disadvantage compared to my other answer: you can't use it twice in the same scope because it declares a variable. However, it may still be interesting for other cases where you want to have somemacro foo run something after foo.

#define my_macro \
    std::ostringstream oss; \
    for (int x=0; x<2; ++x) \
        if (x==1) ThreadSafeLogging(oss.str()); \
        else oss

int main() {
    my_macro << 1 << "hello world" << std::endl;
}
查看更多
登录 后发表回答