Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap std::numeric_limits<T>::max() in parenthesis #595

Merged
merged 1 commit into from
Aug 17, 2023

Conversation

bjornblissing
Copy link
Contributor

The windows.h header file defines the macro max. If the max macro is include it will lead to name collisions with the std::numeric_limits::max() function.

One solution is to define NOMINMAX before the inclusion of windows.h. However, that might be a demanding task for a large codebase. Defining the NOMINMAX as global define may also break previous code.

Another to solution to the problem is to wrap the numeric_limits function in parenthesis to instruct the compiler to treat it as a function and not a macro.

This commit wraps the std::numeric_limits::max() calls in the public interfacing header files, with parenthesis.

The windows.h header file defines the macro max. If the max macro is include
it will lead to name collisions with the std::numeric_limits<T>::max() function.

One solution is to define NOMINMAX before the inclusion of windows.h.
However, that might be a demanding task for a large codebase. Defining the
NOMINMAX as global define may also break previous code.

Another to solution to the problem is to wrap the numeric_limits function in
parenthesis to instruct the compiler to treat it as a function and not a macro.

This commit wraps the std::numeric_limits<T>::max() calls in the public
interfacing header files, with parenthesis.
@wolfpld
Copy link
Owner

wolfpld commented Aug 17, 2023

Another to solution to the problem is to wrap the numeric_limits function in parenthesis to instruct the compiler to treat it as a function and not a macro.

Can you point me to a relevant section in the language standard that has an explanation for this behavior?

@bjornblissing
Copy link
Contributor Author

I am not that well-versed in how to interpret C++-standard language. But I guess that by wrapping the library indentifier protects it from macro substitution in during phase 4 of the lexer.

The C99 standard is a bit more clear:

7.1.4 Use of library functions
Any function declared in a header may be additionally implemented as a function-like macro defined in the header, so if a library function is declared explicitly when its header is included, one of the techniques shown below can be used to ensure the declaration is not affected by such a macro. Any macro definition of a function can be suppressed locally by enclosing the name of the function in parentheses, because the name is then not followed by the left parenthesis that indicates expansion of a macro function name. For the same syntactic reason, it is permitted to take the address of a library function even if it is also defined as a macro.

This is the official recommendation from Microsoft on how to handle name conflicts between library code and macros:
https://learn.microsoft.com/en-us/cpp/c-runtime-library/recommendations-for-choosing-between-functions-and-macros

The solution works for all compilers I have checked:
https://godbolt.org/z/1P73o8TvK

The pattern can already be found in Tracy repo:
Once here:

if (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {

And extensive use in this file:

return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());

@wolfpld
Copy link
Owner

wolfpld commented Aug 17, 2023

Thanks!

@wolfpld wolfpld merged commit 1491e5d into wolfpld:master Aug 17, 2023
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants