Advantage of macro over in-line in C++

2019-02-13 16:42发布

We know that in-line are favorable as they are checked by the compiler and same operation ( like ++x ) does not evaluate more than once when passed as an argument as compared to macros.

But in an interview I was asked the specific advantages or the circumstances when a macro is more favorable to inline in C++.

Does anyone know the answer or can give a thought on this question ?

9条回答
霸刀☆藐视天下
2楼-- · 2019-02-13 16:53

Here is a specific situation where macros are not only preferred, they are actually the only way to accomplish something.

If you want to write a logging function which logs not only some message, but the file & line number of where the instance occured, you can either call your function directly, typing in the file & line values (or macros) directly:

LogError("Something Bad!", __FILE__, __LINE__);

...or, if you want it to work automatically, you must rely on a macro (warning: not compiled):

#define LogErrorEx(ERR) (LogError(ERR, __FILE__, __LINE__))
// ...
LogErrorEx("Something Else Bad!");

This cannot be achieved using templates, default parameters, default construction, or any other device in C++.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-02-13 16:57

A macro is just like a text replacement definition.

These essential differences that come into my mind are:

  • It must not be function-like. I mean it must not necessarily contain some consistent set of brackets for example.
  • It can be used elsewhere. Like in a class declaration scope or even in the global scope. So it must not be in the scope of another function.

You must use them if you want to perform actions that are impossible to be performed using functions:

  • initializing complicated tables (makes core more readable)
  • ease declaration of some special members like event IDs or tag classes (used a lot in MFC IMPLEMENT_DYNAMIC)
  • squeeze repetitive declarations at the beginning of functions
  • the already mentioned use of __LINE__, __FILE__, ... for logging
查看更多
Melony?
4楼-- · 2019-02-13 17:00

The only thing I can think of is there are some tricks that you can do with a macro that can't be done with an inline function. Pasting tokens together at compile-time, and that sort of hackery.

查看更多
做自己的国王
5楼-- · 2019-02-13 17:07

In C++ specifically, one usage of MACROs that seem pop up very often (except for the debug print with file and line) is the use of MACROs to fill in a set of standard methods in a class that cannot be inherited from a base class. In some libraries that create custom mechanisms of RTTI, serialization, expression templates, etc., they often rely on a set of static const variables and static methods (and possibly special semantics for some overloaded operators that cannot be inherited) which are almost always the same but need to be added to any class that the user defines within this framework. In these cases, MACROs are often provided such that the user doesn't have to worry about putting all the necessary code (he only has to invoke the MACRO with the require info). For example, if I make a simple RTTI (Run-Time Type Identification) system, I might require that all classes have a TypeID and be dynamically castable:

class Foo : public Bar {
  MY_RTTI_REGISTER_CLASS(Foo, Bar, 0xBAADF00D)
};   

#define MY_RTTI_REGISTER_CLASS(CLASSNAME,BASECLASS,UNIQUEID) \
  public:\
    static const int TypeID = UNIQUEID;\
    virtual void* CastTo(int aTypeID) {\
      if(aTypeID == TypeID)\
        return this;\
      else\
        return BASECLASS::CastTo(aTypeID);\
    };

The above could not be done with templates or inheritance, and it makes the user's life easier and avoids code repetition.

I would say that this kind of use of MACROs is by far the most common in C++.

查看更多
ら.Afraid
6楼-- · 2019-02-13 17:09

As already said, macros can use preprocessor directives: __FILE__, __LINE__ for instance, but of course #include and #define can also be useful to parameter behaviour:

#ifdef __DEBUG__
#    define LOG(s) std:cout << s << std:endl
#else
#    define LOG(s)
#endif

Depending wether __DEBUG__ is defined or not (via #define or via compiler options), the LOG macro will be active or not. This is an easy way to have debug info everywhere in your code that can be easily de-activated.

You can also think of changing the way memory is allocated (malloc will be redefined to target a memory pool instead of the standard heap for instance, etc...).

查看更多
我只想做你的唯一
7楼-- · 2019-02-13 17:10

I would add two uses:

  1. MIN and MAX, until C++0x, because the return type had to be declared by hand, mixed min and max as inlined functions would have been nightmarish, while a simple macro did it in the blink of an eye.
  2. privacy: you can always undef the macro before exiting your header, you cannot "undeclare" an inline function (or another symbol). This is due to the absence of proper modularity in C and C++ languages.
查看更多
登录 后发表回答