【C++】windows.hインクルード時のmax,min関数エラーを回避する方法

C/C++

C++でWin32デスクトップアプリケーション開発する際に、windows.hをインクルードすることになりますが、このwindows.hの影響でコンパイルエラーが発生してしまう関数があります。

それがC++の標準ライブラリに定義されているmax関数とmin関数です。

例えば以下のコードを見てみましょう。

#include <algorithm>

int main()
{
    int a = 10;
    int b = 20;
    int v1 = std::min(a, b);
    int v2 = std::max(a, b);
}

こちらのコードは何も問題なくコンパイルが通り実行も可能です。

ですが、先ほどのプログラムにwindows.hをインクルードした場合はどうなるでしょうか?

#include <algorithm>
#include <Windows.h>

int main()
{
    int a = 10;
    int b = 20;
    int v1 = std::min(a, b);
    int v2 = std::max(a, b);
}

こちらはコンパイルエラーになります。

実際に実行すると(‘: スコープ解決演算子 (::) の右側にあるトークンは使えません。.構文エラー: ‘)’などがたくさん表示されたかと思います。

Windows.hのインクルードをやめれば解決しますが、そういうわけにもいかないので、max,min関数がコンパイルエラーにならないようにwindows.hをインクルードする方法を解説していきます。

windows.hのインクルードでコンパイルエラーになる理由

windows.hにmaxマクロ関数とminマクロ関数が定義されていることが原因です。

試しにネームスペースのstdを外した状態でコンパイルしてみましょう。

#include <algorithm>
#include <Windows.h>

int main()
{
    int a = 10;
    int b = 20;
    int v1 = min(a, b);
    int v2 = max(a, b);
}

すると何事もなかったかのようにコンパイルが通り実行できるはずです。

このマクロ関数がC++標準ライブラリ(STL)のmax関数とmin関数を上書きしてしまっているために、コンパイルが通らなくなってしまってしまうのです。

max関数・min関数エラーの回避方法

windows.hによるエラーを回避する方法は3つあります。

探せば他にあるかもしれませんが、どれか一つ知っておけば問題ありません。

windows.hインクルード前にNOMINMAXマクロを定義する

一番簡単な方法がNOMINMAXマクロを定義する方法です。

NOMINMAXマクロを定義したあとにwindows.hをインクルードすると、minマクロ関数・maxマクロ関数がそれぞれ定義されなくなり、標準ライブラリのmin,max関数を使ってもコンパイルエラーにならなくなります。

#include <algorithm>

#define NOMINMAX
#include <Windows.h>

int main()
{
    int a = 10;
    int b = 20;
    int v1 = std::min(a, b);
    int v2 = std::max(a, b);
}

NOMINMAXは全て大文字ですので、間違えないようにしてください。

この方法が一番シンプルかつ簡単な方法ですのでおすすめです。

undefでマクロ定義を無効化する

undefで定義済みのマクロを無効化することでも、コンパイルエラーを回避できます。

#include <algorithm>
#include <Windows.h>
#undef min
#undef max

int main()
{
    int a = 10;
    int b = 20;
    int v1 = std::min(a, b);
    int v2 = std::max(a, b);
}

一つ目の方法と比べるとやや面倒ですが、こういう方法もあるということを覚えておくといいかもしれません。

標準ライブラリの関数を優先させる

少しトリッキーな方法ではありますが、関数名をカッコで囲うことでSTLのmax関数・min関数を優先させることができます。

#include <algorithm>
#include <Windows.h>

int main()
{
    int a = 10;
    int b = 20;
    int v1 = (std::min)(a, b);
    int v2 = (std::max)(a, b);
}

できるとは言っても少し変わった書き方になってしまいますし、全てのmin,max関数をこのように書かないといけなくなるのであまりお勧めはしません。

基本的にはNOMINMAX

特に理由がなければ、NOMINMAXマクロを定義してコンパイルエラーを回避する方法を取りましょう。この方法は一番行数を減らせるので、無駄な行動を削減できます。

ですので、基本的にはwindows.hをインクルードする前にNOMINMAXマクロの定義する方法で対策するようにしてください。

Acceliv