我可以为特定功能显式取消定义宏吗?
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
也是个好主意。
#define
ing 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
是您问题的主要解决方案:它抑制了 min
和 max
宏的定义。很可能仍然有必要向 GDI+ header 添加修复程序,它至少最初依赖于 Windows' min
和 max
。但是由于微软的其他不良做法,您通常需要包装每个 Windows header。
STRICT
现在默认定义了,不过定义一下也无妨。它给出了一些函数的 C++ 兼容声明,例如IIRC DialogBox
和朋友们。
上面没有提到的主要配置是_WIN32_WINNT
,主版本宏。还有一些其他版本宏,反映了 Windows API 的不同部分已通过不同方式分别更新,例如通过 Internet Explorer (!) 的更新。几年前曾尝试通过另一种版本控制方案来统一混乱,当然是使用它自己的宏,但也有你主要定义 _WIN32_WINNT
并派生其他版本宏的东西。
我编写了一个模板函数来执行整数的快速对数基数 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
也是个好主意。
#define
ing 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
是您问题的主要解决方案:它抑制了 min
和 max
宏的定义。很可能仍然有必要向 GDI+ header 添加修复程序,它至少最初依赖于 Windows' min
和 max
。但是由于微软的其他不良做法,您通常需要包装每个 Windows header。
STRICT
现在默认定义了,不过定义一下也无妨。它给出了一些函数的 C++ 兼容声明,例如IIRC DialogBox
和朋友们。
上面没有提到的主要配置是_WIN32_WINNT
,主版本宏。还有一些其他版本宏,反映了 Windows API 的不同部分已通过不同方式分别更新,例如通过 Internet Explorer (!) 的更新。几年前曾尝试通过另一种版本控制方案来统一混乱,当然是使用它自己的宏,但也有你主要定义 _WIN32_WINNT
并派生其他版本宏的东西。