Search code examples
c++language-lawyerc-preprocessorpreprocessor

Where in the specification is this way of macro expansion avoidance defined?


Given the following code:

#include <limits>
#include <Windows.h>
int main()
{
    std::numeric_limits<double>::max();
}

I can avoid the preprocessor macro expansion of max() from Windows.h using additional parentheses:

#include <limits>
#include <Windows.h>
int main()
{
    (std::numeric_limits<double>::max)();
}

Does this "feature" have a name? Where in the C++ specification is this "feature" defined? I'd like to know more about it. I searched for "function-like macro", but didn't find relevant entries on this way of avoiding macro expansion.

If version matters, then C++14, but if the principle didn't change, you can also direct me to newer version of the standard.


Solution

  • This is defined by the C++ language. A function-like macro is replaced by its definition only if the non-whitespace character following its name is a (.

    In phase 4 of the translation ("compilation"):

    [lex.phases]/4

    Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed.

    The definition and rules regarding a preprocessing directive is relevant:

    [cpp.replace.general]/12

    A preprocessing directive of the form

    # define identifier lparen identifier-list_opt) replacement-list new-line
    # define identifier lparen ... ) replacement-list new-line
    # define identifier lparen identifier-list , ... ) replacement-list new-line
    

    defines a function-like macro with parameters, whose use is similar syntactically to a function call. The parameters are specified by the optional list of identifiers. Each subsequent instance of the function-like macro name followed by a ( as the next preprocessing token introduces the sequence of preprocessing tokens that is replaced by the replacement list in the definition (an invocation of the macro). The replaced sequence of preprocessing tokens is terminated by the matching ) preprocessing token, skipping intervening matched pairs of left and right parenthesis preprocessing tokens. Within the sequence of preprocessing tokens making up an invocation of a function-like macro, new-line is considered a normal whitespace character.