【C++跨平台系列】解决STL的max()与numeric_limits::max()和VC6 min/max 宏冲突问题

多年以前,Microsoft 幹了一件比 #define N 3 還要蠢的蠢事,那就是在 <windows.h> 放入了 min/max 這兩個宏命令(macros)。

     #define max(a,b)            (((a) > (b)) ? (a) : (b))

因此,我們沒辦法好好地使用 C++ Standard 的 min/max 這兩個 algorithms,也沒有辦法好好地使用 numeric_limits<>。前者 Microsoft 用了另外兩個宏命令,_MIN_MAX 來補救,但考量到跨平台程式設計,這兩個 macros 有跟沒有一樣。

     #define _MAX _cpp_max      ——>     const T& std::_cpp_max(const T&,const T&);

後者就真的很傷腦筋了,很多時候,numeric_limits<> 的使用是無法避免的[1]

     [1]舉例來說,為了跨平台的需求,我們無法得知 size_t 的真正型別,故無法直接使用 C 的 UINT_MAX 來表現 size_t 的最大可能值。最好的方法,當然還是使用 numeric_limits<size_t>::max()

但當直接或間接 #include<windows.h> 的時候,VC6 就會出現 C4003 warning 然後後面的程式就爛掉了。

通常來說,碰到這種相容性問題,先找看看 Boost 怎麼作就對了。(因為 Boost 裡面充滿了各種各樣最先進的 C++ 技術,而先進的 C++ 技術通常都會碰到相容性問題,因此 Boost 裡面就會有比較合適的解法存在。)於是我在 boost/config/suffix.hpp 裡,發現了 BOOST_PREVENT_MACRO_SUBSTITUTION 這一個宏命令,被安插在可能被 VC6 搞爛的 min/max 後面,括弧前面。其用法如下:

std::max BOOST_PREVENT_MACRO_SUBSTITUTION(value1, value2);
// or
std::numeric_limits<Foo>::max BOOST_PREVENT_MACRO_SUBSTITUTION();

實際上,BOOST_PREVENT_MACRO_SUBSTITUTION 是空的,會被代換成沒有任何東西,其目的應該是為了騙過 preprocessor,使其認為 min/max 不是 VC6 雞婆定義的那個 macro,而留給 compiler 來剖析之。

不過,照著這招做實驗後發現,沒有用。也許是 Boost 還有其他機制,讓這招成功,但總之我就是弄不出來,BOOST_PREVENT_MACRO_SUBSTITUTION 會先被 preprocessor 代換成沒有任何東西,然後原來的 min/max 的問題就又出現了。

只好求助 Google,幸好讓我發現了這串討論:《problems with new boost lib》,裡面提到可以使用括弧,來避免 preprocessor 作怪。也就是說,程式改成這麼寫:

(std::max)(value1, value2);
// or
(std::numeric_limits<Foo>::max)();

min/max 連同前面的 namespace 括弧刮起來再接上呼叫用的 (),這樣就既是合法的 C++ 語法,又可以避免愚鈍的 preprocessor 被白爛 VC6 的 min/max 宏命令騙去


posted on 2011-01-30 10:02  cvbnm  阅读(3744)  评论(0编辑  收藏  举报

导航