简体   繁体   English

如何在 c++ 中使用宏?

[英]How to use Macros in c++?

Recently I came across inline in c++17 and how it been used as an alternative to #define but both have its downsides.最近我在 c++17 中遇到了 inline 以及它如何被用作#define的替代品,但两者都有其缺点。 However my question is that if I want to cramp the whole std::cout << x << '\n';但是我的问题是,如果我想抽筋整个std::cout << x << '\n'; in one simple line called LOG(x) .在一个名为LOG(x)的简单行中。

A: What should I use and why?答:我应该使用什么,为什么?
B: What are the pros and cons of each and when to use what? B:各有什么优缺点,什么时候用什么?

1.) 1.)

#define LOG(x) std::cout << x << '\n'

2.) 2.)

void inline LOG(auto x)
{
    std::cout << x << '\n';
}

3.) 3.)

void LOG(auto x)
{
    std::cout << x << '\n';
}

4.) 4.)

This one was suggested to me by someone:这个是有人推荐给我的:

template <typename T>
void log(const T& x)
{
    std::cout << x << '\n';
}

How to use Macros in c++?如何在 c++ 中使用宏?

Sparingly.谨慎。 When there is no better alternative.当没有更好的选择时。


  1. Avoid this.避免这种情况。 Macros names don't respect scoping rules and thus are much more susceptible to name clashes.宏名称不遵守范围规则,因此更容易受到名称冲突的影响。 Also, consider what happens if you wanted to log a number bitshifted by another number:另外,考虑一下如果你想记录一个被另一个数字移位的数字会发生什么:

     LOG(0x1 << 2);

    What output would you expect, and what output do you get?你会期待什么 output,你会得到什么 output? Do they match?他们匹配吗?

  2. Pro: It is a function (template) and thus doesn't have the problems associated with macros.亲:它是一个 function(模板),因此不存在与宏相关的问题。 Con: You accept the parameter by value.缺点:您按值接受参数。 This can be expensive with for example strings which are quite often used for logging.例如,经常用于日志记录的字符串可能会很昂贵。 Requires C++20.需要 C++20。

  3. Practically identical to 2. The auto parameter turns these into function templates which are implicitly inline.实际上与 2 相同。 auto参数将这些转换为隐式内联的 function 模板。

  4. Pro: Doesn't require C++20.优点:不需要 C++20。 A reference is passed, which is good for passing strings.传递了一个引用,这对于传递字符串很有好处。

In conclusion: 4. is a reasonable default choice.结论:4.是一个合理的默认选择。

The general consensus is that using macros is not a good idea.普遍的共识是使用宏不是一个好主意。 BUT what that really means is that ABUSE of macros is not a good idea.但这真正意味着滥用宏不是一个好主意。

Solution #2 is OK, but its usefulness is rather limited, since you can only print one value per line.解决方案#2 可以,但它的用处相当有限,因为每行只能打印一个值。

inline void LOG(const auto& x)
{
    std::cout << x << '\n';
}

// use as:
LOG(x);

And it's an OK solution, but its usage is rather limited.. Consider this use case:这是一个不错的解决方案,但它的使用相当有限。考虑这个用例:

inline void LOG(const auto& x)
{
    std::cout << x << '\n';
}

struct point { float x, y; };

// usability is kind of limited, since it will only print one value per line 
point p{};
LOG(x);
LOG(y);

// which gives this output.
0
0

// That's not really useful for a log.

One advantage of the macro, is that you could make your log output a bit more useful.宏的一个优点是,您可以使日志 output 更有用一些。

#define LOG(x) std::cout << x << '\n'

struct point { float x, y; };

// usability is better, but still limited, 
point p{};
LOG("x: " << p.x << ", y: " << p.y);

// which gives this output.
x: 0, y: 0

That's a bit better, you are using a macro, and you do have more control over the output, making your log more useful.这有点好,您正在使用宏,并且您确实可以更好地控制 output,从而使您的日志更有用。 But it puts some limitations on your code... For example, you may want, at a later date, to use a third party logging library, or write your own, but some calls to LOG() will have operators in them, and this may force you to rewrite them.但它对您的代码施加了一些限制......例如,您可能希望在以后使用第三方日志库,或者编写自己的日志库,但是对 LOG() 的某些调用将在其中包含运算符,并且这可能会迫使您重写它们。

For this reason, among others, a function template would be better, one that accepts any number of arguments.因此,除其他外,function 模板会更好,它可以接受任意数量的 arguments。

template <typename... Args>
inline void LOG(Args&&... args)
{
    (std::cout << ... << args) << '\n';
}

point p{};

LOG("x: ", p.x, ", y: ", p.y);

// which gives this output.
x: 0, y: 0

If you want to defeat logging in your release version, I suggest using a macro.如果你想在你的发布版本中失败,我建议使用宏。

#define LOG(...)

// on MSVC
#define LOG(...) __noop

I wouldn't use #1 (macro version) unless you want to log the symbol name of the variable in the output, such as:除非您想在 output 中记录变量的符号名称,否则我不会使用 #1(宏版本),例如:

#define LOG(x) std::cout << #x << " = " << x << '\n' 

I believe #2 and #4 are equivalent, as using auto introduces a template type under the hood.我相信 #2 和 #4 是等价的,因为使用 auto 在引擎盖下引入了模板类型。

#3 is slightly inferior as it requires you to write a declaration in a header file as well as putting the definition in a source file (since it is not inline), which is more code to maintain. #3 略逊一筹,因为它要求您在 header 文件中编写声明,并将定义放在源文件中(因为它不是内联的),这需要更多代码来维护。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM