无论如何,是否可以将以下内容写为 C++宏?

发布于 2024-08-20 00:58:57 字数 298 浏览 9 评论 0原文

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

应该扩展到:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

八巷 2024-08-27 00:58:57
#define my_macro my_stream()
class my_stream: public std::ostringstream  {
public:
    my_stream() {}
    ~my_stream() {
        ThreadSafeLogging(this->str());
    }
};
int main() {
    my_macro << 1 << "hello world" << std::endl;
}

创建一个 my_stream 类型的临时文件,它是 ostringstream 的子类。对该临时对象的所有操作都像在 ostringstream 上一样工作。

当语句结束时(即在 main() 中整个打印操作的分号之后),临时对象超出范围并被销毁。 my_stream 析构函数使用之前“收集”的数据调用 ThreadSafeLogging

已测试(g++)。

感谢/感谢 dingo 指出如何简化整个事情,所以我不知道不需要重载的运算符<<。可惜投票不能分享。

#define my_macro my_stream()
class my_stream: public std::ostringstream  {
public:
    my_stream() {}
    ~my_stream() {
        ThreadSafeLogging(this->str());
    }
};
int main() {
    my_macro << 1 << "hello world" << std::endl;
}

A temporary of type my_stream is created, which is a subclass of ostringstream. All operations to that temporary work as they would on an ostringstream.

When the statement ends (ie. right after the semicolon on the whole printing operation in main()), the temporary object goes out of scope and is destroyed. The my_stream destructor calls ThreadSafeLogging with the data "collected" previously.

Tested (g++).

Thanks/credits to dingo for pointing out how to simplify the whole thing, so I don't need the overloaded operator<<. Too bad upvotes can't be shared.

不奢求什么 2024-08-27 00:58:57

难道你不能从 ostream 派生并提供你自己的线程安全实现吗?那么您可以

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

在没有宏的情况下正确使用 C++ 并获得完全相同的功能吗?

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?

落花浅忆 2024-08-27 00:58:57

问题是,如果不使用函数语法,宏就只能在其所在位置进行替换。

但是如果您愿意使用函数语法,则可以替换参数之前和之后的内容。

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

您可以将 MyMacro 定义为:

#define my_macro(args) std::ostreamstring oss; \
                       oss << args; \
                       ThreadSafeLogging(oss.str());

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());
世俗缘 2024-08-27 00:58:57

看看 google-glog,他们使用一个用 a 实例化的临时对象来做​​到这一点

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

,他们也有其他有趣的宏,例如 LOG_IF 等。

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.

心如荒岛 2024-08-27 00:58:57

考虑到您的代码中包含了这些行,是的,

#include <iostream>
#include <sstream> 

所有标准编译器都可能定义了 __LINE__ 宏。
因此,我们可以使用它来生成一个变量名,每次使用宏时该变量名都不同:)

这是一个新版本,仅被视为单语句指令:
(已编辑)

#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; 
} 

由于运算符 << 的简单性,开发人员可能不需要在同一行上使用该宏两次。但如果您需要这个,您可以将 __LINE__ 的使用切换为 __COUNTER__ (这是非标准的!)。感谢 Quuxplusone 提供的建议

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

谜泪 2024-08-27 00:58:57

这是我在其他地方看到的另一个令人讨厌的把戏。与我的其他答案相比,它有一个显着的缺点:您不能在同一范围内使用它两次,因为它声明了一个变量。但是,对于其他情况(您希望somemacro foofoo之后运行某些内容)可能仍然很有趣。

#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;
}

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;
}
音盲 2024-08-27 00:58:57

我的日志记录设置非常相似:

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)

如果您的日志记录被禁用,则永远不会创建 ostream,并且存在很少的开销。您可以配置日志记录文件名和名称。行号或优先级。 ShouldLog 函数可以在调用之间更改,因此您可以限制或限制输出。日志输出使用两个函数来修改自身,Prefix 向行添加“file:line: (PRIO)”前缀,Flush() 既将其作为单个命令刷新到日志输出,并向其添加换行符。在我的实现中,它总是如此,但如果还不存在,您可以将其作为条件。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文