Microsoft has std::max()
in <utility>
, so this compiles (Godbolt):
#include <utility>
int main()
{
return std::max(2,3);
}
GCC doesn't have std::max()
in <utility>
, so it doesn't compile (Godbolt). And neither does clang (Godbolt).
CppReference doesn't list it as part of <utility>
. It should be in <algorithm>
(CppReference).
The MSVC header <utility>
does not #include <algorithm>
as allowed per [res.on.headers] (see this answer). Instead, it implements 2 functions directly and forward-declares others:
_EXPORT_STD template <class _Ty, class _Pr>
_NODISCARD constexpr const _Ty&(max) (const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept(
noexcept(_Pred(_Left, _Right))) /* strengthened */ {
// return larger of _Left and _Right
return _Pred(_Left, _Right) ? _Right : _Left;
}
#pragma warning(push)
#pragma warning(disable : 28285) // (syntax error in SAL annotation, occurs when _Ty is not an integral type)
_EXPORT_STD template <class _Ty>
_NODISCARD _Post_equal_to_(_Left < _Right ? _Right : _Left) constexpr const _Ty& //
(max) (const _Ty& _Left, const _Ty& _Right) noexcept(noexcept(_Left < _Right)) /* strengthened */ {
// return larger of _Left and _Right
return _Left < _Right ? _Right : _Left;
}
#pragma warning(pop)
_EXPORT_STD template <class _Ty, class _Pr>
_NODISCARD constexpr _Ty(max)(initializer_list<_Ty>, _Pr); // implemented in <algorithm>
_EXPORT_STD template <class _Ty>
_NODISCARD constexpr _Ty(max)(initializer_list<_Ty>); // implemented in <algorithm>
Is it allowed for a library vendor (like Microsoft) to add functions to arbitrary headers?
The problem I see is portability of my code. This way, my code only works with MSVC and not with others. Worse, I ended up in this situation because I used the feature "Optimize include graph" of Visual Studio, which then decided that <utility>
requires less lines of code to be included (or whatever their metric is to optimize includes).
In the Standard, I only find (search term const T& max
) the std::max() function in chapter "Header <algorithm> synopsis" (chapter 27.4 in C++23 draft N4928).
This question is not a duplicate of Why does omission of "#include " only sometimes cause compilation failures?. I know why it compiles. It compiles because std::max()
is defined directly or indirectly in <utility>
. None of the answers there gives a reference to the specification.
Same for Why can std::max and std::min still be used even if I didn't #include ? and Can std::string be used without #include ? and Why Is it possible to use std::thread without #include thread in c++? . Those not language-lawyer questions and none of them gives specification references.
using.headers#3 says:
A translation unit [...] shall include the header [...] lexically before the first reference in that translation unit to any of the entities declared in that header. No diagnostic is required.
The code references std::max
, but includes only <utility>
. Yet, utility.syn does not list max
anywhere. Therefore, the program has undefined behavior is ill-formed, no diagnostic required.
That the program still compiles, does not make it correct. Nevertheless, the compiler is conforming because it is not required to diagnose that <algorithm>
, where std::max
is actually declared, was not included.