【问题标题】:Why is std::min failing when windows.h is included?为什么包含 windows.h 时 std::min 失败?
【发布时间】:2011-02-15 14:26:55
【问题描述】:
#include <algorithm>
#include <Windows.h>

int main()
{
    int k = std::min(3, 4);
    return 0;
}

如果我包含 Windows.h,Windows 会做什么?我无法在 Visual Studio 2005 中使用std::min。错误信息是:

error C2589: '(' : illegal token on right side of '::'
error C2059: syntax error : '::'

【问题讨论】:

标签: c++ visual-studio-2005


【解决方案1】:

windows.h 头文件(或更准确地说,它依次包含的windef.h)具有干扰minmax 的宏。

您应该在包含它之前#define NOMINMAX

【讨论】:

  • 宏是邪恶的原因之一。 :D
  • 我使用了项目范围的 /D "NOMINMAX"
  • @Micka:你把这个选项放在你的项目设置中的什么地方?我必须使用相同的选项,我不知道该放在哪里......
  • @flaviu2 在页面上的“附加命令”字段中汇总了所有编译命令。但目前无法查看
  • 因为它是添加:#include + NOMINMAX
【解决方案2】:

无需定义任何东西,只需使用以下语法绕过宏:

(std::min)(a, b); // added parentheses around function name
(std::max)(a, b);

【讨论】:

  • 谢谢,这是对我有用的解决方案。我正在编写一个不能简单地使用 NOMINMAX 的代码,因为代码的某些部分使用来自 Windows 的需要宏的绘图代码。
  • 你能解释一下为什么魔法周围的括号可以打败邪恶的宏!?酷
  • 我不完全确定引擎盖下的所有魔法,但我相信宏解析器正在寻找完全替换“min(”,因此宏解析器忽略了“min)(” . 用无意义的 () 包装的函数名不会导致宏之外的任何问题。
  • 简洁的解决方案,但不能解决名称为 minmax 的函数的问题(示例用例:实现一个符合 UniformRandomNumberGenerator 概念的类) .
  • 请看 Erik 的回答,我认为这是一个更好的解决方案。不那么老套,更清晰。
【解决方案3】:

我首选的解决方案是像这样使类型显式:

auto k = std::min<int>(3, 4);

这也会阻止预处理器匹配min,并且可以说比括号解决方法更具可读性。 NOMINMAX 解决方案的一个问题是,当您的代码在下一个项目中被重用时,您(或其他人)必须重新开始询问为什么这个“工作”代码不再编译。

但是要回答实际问题为什么会失败?

Windows.h 文件包括定义以下宏的windef.h

#ifndef NOMINMAX
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
#endif

预处理器本质上是通过查找代码中的字符序列(包括左括号)来扩展宏,在本例中为min(。然后它对您的代码进行基本搜索/替换,因此在预处理器步骤之后您的代码变为:

int k = std::((3)<(4)?(3):(4));

编译器步骤(仅包含此修改后的代码)在尝试编译 std::( 时会失败,并给出错误消息。

您现在还可以查看此页面上提出的各种修复/解决方法的工作原理:

  1. 在包含windef.h 之前定义NOMINMAX 意味着这些宏不会被定义,因此编译器可以编译std::min
  2. 将括号括在std::min 周围意味着预处理器不再看到序列min(,因此不理会它。
  3. 放入模板参数意味着min&lt;也不匹配宏。

【讨论】:

  • 我同意,这是最好的解决方案。当我看到其他人击败我时,我刚回来给出另一个答案。
【解决方案4】:

正如其他人所提到的,错误是由于 Windows 标头中定义的最小/最大宏造成的。可以通过三种方式禁用它们。

1) #define NOMINMAX 在包含标头之前,这通常是一种不好的定义宏以影响以下标头的技术;

2) 在编译器命令行/IDE 中定义NOMINMAX。这个决定的坏处是,如果你想发布你的资源,你需要警告用户也这样做;

3) 只需在使用之前取消定义代码中的宏

#undef min
#undef max

这可能是最便携和灵活的解决方案。

【讨论】:

  • 选项 1 的另一个问题是它并不总是有效。其他地方可能包含其他实际需要它的 Windows 标头,例如 gdiplus.h。在这种情况下,选项 3 可能是您唯一的希望。
【解决方案5】:

试试这样的:

#define NOMINMAX
#include <windows.h>

默认情况下,windows.h 将minmax 定义为宏。当这些被扩展时,尝试使用std::min(例如)的代码最终会看起来像这样:

int k = std::(x) < (y) ? (x) : (y);

错误消息告诉您std::(x) 是不允许的。

【讨论】:

    【解决方案6】:

    就我而言,项目没有明确包含windows.hwindef.h。它正在使用Boost。因此,我通过转到项目 Properties -&gt; C/C++ -&gt; Preprocessor 并在 Preprocessor Definitions 中附加 NOMINMAX 解决了这个问题(VS 2013,VS 2015)。

    【讨论】:

    • 对于 VS 2015,在文件中定义宏对我不起作用。在项目中定义是有效的。
    【解决方案7】:

    对于包括 windows.h 在内的人,将以下内容放在受影响的标题中:

    #include windows headers ...
    
    pragma push_macro("min")
    pragma push_macro("max")
    #undef min
    #undef max
    
    #include headers expecting std::min/std::max ...
    
    ...
    
    pragma pop_macro("min")
    pragma pop_macro("max")
    

    在源文件中只有 #undef min 和 max。

    #include windows headers ...
    
    #undef min
    #undef max
    
    #include headers expecting std::min/std::max ...
    

    【讨论】:

      【解决方案8】:

      为了解决这个问题,我只创建了名为 fix_minmax.h 的头文件 without include guards

      #ifdef max
          #undef max
      #endif
      
      #ifdef min
          #undef min
      #endif
      
      #ifdef MAX
          #undef MAX
      #endif
      #define MAX max
      
      #ifdef MIN
         #undef MIN
      #endif
      #define MIN min
      
      #include <algorithm>
      using std::max;
      using std::min;
      

      基本用法是这样的。

      // Annoying third party header with min/max macros
      #include "microsoft-mega-api.h"
      #include "fix_minmax.h"
      

      这种方法的优点是它适用于所有类型的包含文件或部分代码。在处理依赖于min/max 宏的代码或库时,这也可以节省您的时间

      【讨论】:

        【解决方案9】:
        #define NOMINMAX
        

        是抑制 max 和 min 宏定义的技巧

        http://support.microsoft.com/kb/143208

        【讨论】:

          【解决方案10】:

          我假设 windows.h 确实将 min 定义为宏,例如喜欢

          #define min(a,b)  ((a < b) ? a : b)
          

          这将解释错误消息。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-03-03
            • 1970-01-01
            • 2020-10-29
            • 2012-12-02
            • 1970-01-01
            • 2011-09-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多