It isn't an easy problem. One of the main offenders in this case
is <windows.h>. I've never found a reassurance in Microsoft
documentation that their min/max macros are not used in their
own functions. This means that using NOMINMAX in your code and
linking to something else that doesn't use it could potentially
lead to ODR violations.
Indeed.
Some years ago (I think less than a decade) I posted a min/max-fixed
version of Microsoft's <gdiplus.h>.
Checking, it still uses the min/max macros from <windows.h>, as of
Visual C++ 2013 (version 12.0):
<code>
#define NOMINMAX
#include <Windows.h>
#include <gdiplus.h>
auto main() -> int
{
MessageBox( 0, L"Hi", L"Info:", MB_SETFOREGROUND );
}
</code>
<compilation result>
1>c:\program files (x86)\windows
kits\8.1\include\um\gdiplustypes.h(500): error C3861: 'max': identifier
not found
1>c:\program files (x86)\windows kits\8.1\include
.... etc.
</compilation result>
<gdiplus.h> is mainly a header-only C++ module that wraps the separately
compiled GDI+ C API, i.e. a C++ language binding to that API, Microsoft
style. Happily most of the code is in a C++ namespace. So my old fix was
to add "using std::min" and "using std::max" in that namespace, as well
as a common include of <algorithm>, but this entailed fixing a lot of
sub-headers -- I don't recall exactly why now, but it was a lot of
editing, not a simple quick-fix.
(I think they do not use them; but that's not a certainty.)
See above.
Up until a few weeks ago, I've been avoiding the names "min" and
"max" in my own code, exactly to avoid problems. Then, I wrote a
little class intended to be a model of standard uniform random
number generator; and that *requires* those names.
To protect those names (including if you use
numeric_limits<>::min/max), you have two main alternatives:
either you parenthesize or you use a dummy macro like this:
#define NO_MACRO_EXPANSION
int x = std::numeric_limits< int >::max NO_MACRO_EXPANSION () ;
It prevents expanding any function-like macro named "max" for
the same reason that a ')' does: the macro name isn't followed
by an open parenthesis.
Well I think neither alternative is open for 3rd party code that one
includes.
So I think that the only reasonable way to do things is to define
NOMINAX and make sure to include <windows.h> oneself before including
any other headers.
That, by the way, is also necessary to avoid inconsistencies with
respect to supported OS version etc. (what declarations are included,
and even the form of the declarations).
Cheers,
- Alf