yohhoyの日記

2012-01-15

windows.hのmin/maxマクロ回避策4パターン

Microsoft Windowsプラットフォームのヘッダファイルwindows.hは悪名高いmin, maxマクロを定義するため、プリプロセス時に意図せずminやmaxが置換されてしまい、妙なコンパイルエラーを引き起こす場合がある。一例としてMSVC10で下記コードをコンパイルすると、それぞれエラーメッセージが出力される。

#include <windows.h>
#include <numeric>

//-------- Case 1
int a = 1, b = 2;
int x = std::min(a, b);
//  error C2589: '(' : スコープ解決演算子 (::) の右側にあるトークンは使えません。
//  error C2059: 構文エラー : '::'

//-------- Case 2
double maxvalue = std::numeric_limits<double>::max();
//  warning C4003: マクロ 'max' に指定された実引数の数が少なすぎます。
//  error C2589: '(' : スコープ解決演算子 (::) の右側にあるトークンは使えません。
//  error C2059: 構文エラー : '::'

回避策1:マクロ定義を行なわせない

ヘッダファイルwindows.hのincludeより前に、マクロ NOMINMAX を定義しておく。Microsoft KBで公開されている正攻法。

#define NOMINMAX
#include <windows.h>

回避策2:マクロ定義を無効化する

ユーザが明示的にマクロのundefを行う。

#include <windows.h>
#undef min
#undef max

回避策3:プリプロセッサによるマクロ展開を抑止する(1)

minやmaxを含む式を括弧でくくり*1、関数形式マクロ(function-like macro)として扱われないようにする。

//-------- Case 1
int x = (std::min)(a, b);  // OK
//-------- Case 2
double maxvalue = (std::numeric_limits<double>::max)();  // OK

回避策4:プリプロセッサによるマクロ展開を抑止する(2)

Boost.Config提供のマクロ BOOST_PREVENT_MACRO_SUBSTITUTION をminやmaxの直後に配置し、関数形式マクロとして扱われないようにする。

#include <boost/config.hpp>

//-------- Case 1
int x = std::min BOOST_PREVENT_MACRO_SUBSTITUTION (a, b);  // OK
//-------- Case 2
double maxvalue = std::numeric_limits<double>::max BOOST_PREVENT_MACRO_SUBSTITUTION ();  // OK

Boost Library Requirements and Guidelinesによると同マクロは、(1)min/maxを名前空間を指定せずADL経由で呼び出したいとき、または(2)クラスメンバ関数名としてmin/maxを宣言定義するときに用いる。

*1:より正確には識別子min/maxに続くトークンとして、左括弧(lparen) ( が出現しないようにする。

egtraegtra 2016/12/13 00:26 回避策1のところのKBへのリンクが切れています。現在のURLはこちらのようです。
https://support.microsoft.com/en-us/kb/143208

yohhoyyohhoy 2016/12/13 09:57 ありがとうございます。Microsoft KBへのリンク修正しました。
(たまーにみるとURL変わってるような気がする…)

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証