我可以为特定功能显式取消定义宏吗?

Can I explicitly undefine a macro for particular function?

我编写了一个模板函数来执行整数的快速对数基数 2。它在我的测试程序中有效,但是当我将它粘贴到我的主项目中时,我发现 windows.h header 有问题。问题是我使用的是 c++ std::numeric_limits<T>::max() 函数,但是 windows.h 包含一个也称为 max 的宏,作为一个宏,它不是命名空间感知的并且覆盖了我尝试使用真实的C++函数。无论如何,除了不包括 windows.h 之外,我还能避免这种情况吗? (这不是一个真正的选择)

这是我的函数:

// Returns x where x = log2(n)
template<typename T>
T log2i(T n)
{
    static const T infinite(std::numeric_limits<T>::max());
    T x = 0;

    if (n == 0)
    {
        return infinite;
    }
    if (n > 1)
    {
        while (n >>= 1)
        {
            ++x;
        }
    }

    return x;
} 

每当我需要 #include <windows.h> 时,我都会使用

#define byte byte_for_windows_include
#include <windows.h>
#undef byte

#ifdef max
#    undef max
#endif
#ifdef min
#    undef min
#endif

<windows.h> 还将 byte 的定义发送到全局命名空间中,这可能很麻烦。

#define STRICT 也是个好主意。

#defineing NOMINMAX 在过去被证明是不可靠的。

static const T infinite((std::numeric_limits<T>::max)());

会起作用:额外的括号会阻止宏扩展。

windows.h 依赖于一些配置符号。

要正确使用此 header,您需要将其包装起来,以便在任何地方都获得相同的定义。

最小包装器 header:

#pragma once

#undef  STRICT
#define STRICT
#undef  NOMINMAX
#define NOMINMAX
#undef  UNICODE
#define UNICODE
#undef  WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

同时使用 g++ 和 MSVC WIN32_LEAN_AND_MEAN 将行数减少到大约一半。对于 g++,我们谈论减少大约 60 000 → 30 000 行,而对于 MSVC,减少 300 000 → 150 000 行。翻译单元减少 150 000 行是恕我直言,足以默认定义此符号。

UNICODE 导致 <windows.h> 宏如 CreateWindow (以及所有成千上万类似的函数名称宏)扩展为 CreateWindowW(Unicode wchar_t 变体)而不是 CreateWindowA(ANSI char 兼容性变体),并导致 TCHAR 映射到 wchar_t 而不是 char。对于runtime库可以考虑定义_UNICODE对应UNICODE,定义_MBCS会报错

NOMINMAX 是您问题的主要解决方案:它抑制了 minmax 宏的定义。很可能仍然有必要向 GDI+ header 添加修复程序,它至少最初依赖于 Windows' minmax。但是由于微软的其他不良做法,您通常需要包装每个 Windows header。

STRICT现在默认定义了,不过定义一下也无妨。它给出了一些函数的 C++ 兼容声明,例如IIRC DialogBox 和朋友们。

上面没有提到的主要配置是_WIN32_WINNT,主版本宏。还有一些其他版本宏,反映了 Windows API 的不同部分已通过不同方式分别更新,例如通过 Internet Explorer (!) 的更新。几年前曾尝试通过另一种版本控制方案来统一混乱,当然是使用它自己的宏,但也有你主要定义 _WIN32_WINNT 并派生其他版本宏的东西。