如何处理Windows.h中的max宏与std中的max发生冲突?

84

所以我尝试从cin获取有效的整数输入,并使用了这个问题的答案。

它建议:

#include <Windows.h> // includes WinDef.h which defines min() max()
#include <iostream>
using std::cin;
using std::cout;

void Foo()
{
    int delay = 0;
    do
    {
        if(cin.fail())
        {
            cin.clear();
            cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
        cout << "Enter number of seconds between submissions: ";
    } while(!(cin >> delay) || delay == 0);
}

这在Windows上会导致错误,提示max宏不接受那么多参数。这意味着我必须这样做:

do
{
    if(cin.fail())
    {
        cin.clear();
#undef max
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    cout << "Enter number of seconds between submissions: ";
} while(!(cin >> delay) || delay == 0);
为了使它能够工作。这很丑陋; 有没有更好的方法来解决这个问题?也许我应该存储max的定义并在之后重新定义它?

为了解决这个问题,需要一个可行的办法。存储max的定义并在之后重新定义可能是一种更好的解决方案。


7
你是否包含了<Windows.h>?为什么?如果你确实需要它,可以在包含它之前定义NOMINMAX来避免定义_min_和_max_宏。 - Piotr Tkaczyk
1
你正在使用 "namespace std" 吗?如果是这样,你正在有意地合并命名空间。 - Paul Beckingham
8
@PaulBeckingham说:宏没有命名空间,因此在没有任何预防措施的情况下包含windows.h头文件将始终与std::min/std::max发生冲突。 - PlasmaHH
1
可能是[带有min()/max()调用的代码出现奇怪的C++错误]的重复问题。(https://dev59.com/WEXRa4cB1Zd3GeqPoAHU) - PlasmaHH
请查看以下链接以了解有关宏和成员函数冲突的问题:https://dev59.com/MXM_5IYBdhLWcg3wZSTX - Mr. Ree
6个回答

127

定义宏NOMINMAX

这将抑制Windef.h中的min和max定义。


6
由于某些原因,即使https://support.microsoft.com/en-us/search?query=NOMINMAX被返回为唯一的匹配项,但该网址对我无法使用。 - malat

98

只需要在函数名外加上括号即可:

(std::numeric_limits<size_type>::max)()

在这种情况下不需要使用NOMINMAX宏,而且您也不会收到编译器警告。


2
std::max<size_type>(a,b) 对我来说很有效,并且更易读。模板参数抑制了宏。我有什么遗漏吗? - Dale Wilson
4
@DaleWilson 是的,你漏掉了一些东西。你的调用将得到两个值中较大的一个。std::numeric_limits<size_type>::max()将返回可以由size_type存储的最大值。 - Ben
2
将函数名用括号括起来是将函数指针包装起来,并通过函数指针实现策略模式。这违反了直接在代码中表达思想的建议,因为这种语法更像是尝试绕过min和max宏定义的定义(而不是通过函数指针实现策略模式)。Clang/LLVM基础设施建议在任何Windows头文件之前使用"#define NOMINMAX"。在我看来,这是更好的建议。 - Louis Langholtz
2
@LouisLangholtz 在使用VS项目时,通常会有一个名为stdafx.h的公共文件。当您在其中放置NOMINMAX时,其他使用宏的文件可能会出现错误。 - ggurov
1
当处理包含旧的max和min宏的遗留代码的项目时,这是您最好的选择。丑陋的语法是一种权衡。 - jakar
显示剩余2条评论

13

如果你不确定其他人是否已经包含了windows.h而没有使用NOMINMAX,你可以定义一个虚拟宏来抑制函数样式的宏调用,而不改变定义:

#define DUMMY
...
std::numeric_limits<std::streamsize>::max DUMMY ()

这种方法不算很美观,但是它能够正常工作且不会产生干扰。

在使用Windows头文件时,我喜欢尽可能地隐藏它,只在专门的代码和头文件中包含它(如有必要使用Pimpl),因为它会将大量垃圾扔进全局命名空间。


3
有趣。我一定会遵循建议,尽可能地剥离 windows.h。 - Almo
当为他人编写头文件并且您无法控制用户在您的头文件之前是否包含windows.h时,这是一种非常好的做法。 - Phil Rosenberg

11

你只是想清空 cin 缓冲区吗?我通常使用以下方法:

cin.ignore(cin.rdbuf()->in_avail());

这是一个很好的答案,虽然我已经接受了另一个答案,因为它直接回答了问题,而你的回答则从另一个角度解决了问题的根源。 :) - Almo

7

如果您使用的是GDI+,那么使用NOMINMAX方法将无法奏效,因为GDI+头文件要求在全局命名空间中使用minmax

在这种情况下,最简单的解决方法是在不再需要min/max时取消定义它们。

以下是示例代码:

//#define NOMINMAX - this won't work
#include <Windows.h>
#include <gdiplus.h>
#undef max
#undef min
...
#include <cxxopts.hpp>

1
这可能会导致问题的反转:如果头文件中发生名称冲突,则可以按照这里的描述解决,并且您在某个地方包含此头文件,需要定义尚未定义的min/max - 那就倒霉了... - Aconcagua

2

我来到这里寻找一个常见的windows.h定义列表,经过长时间的搜索,我找到了min, max, small, near, far. 希望这也能帮助其他人。

我知道这个问题已经有10年了,但是没有人给出明显的解决方案,所以这是我处理此问题的方法。

所有与操作系统相关的内容都放在一个翻译单元(一个CPP源文件)中,为项目的其余部分提供更清晰的API,因此windows.h从不污染项目的其余部分。任何与操作系统相关的句柄都是“NativeHandle”,它被typedef为void *; 一些东西以这种方式堆分配可能不需要,但考虑到这也为移植到其他平台提供了一个单一的源点,这并不是很大的缺点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接