minとmaxとwindowsのマクロ

STLには2つの変数の大きい方もしくは小さい方を返す関数がある。minとmaxである。内容は簡単なので自前で作っても大した手間ではない。

template< class A >
A max( const A& a, const A& b ){
	return a > b ? a : b;
}

しかし簡単でも自作するより標準関数を利用した方が品質がよいのは言うまでもない。


しかしこの関数、windowsアプリ作る場合には困ったことにマクロで定義してあったりする。

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

まあこの関数自体がマクロ関数で定義されること自体はそれほど悪いことではないが、普通に使っていてもよくぶつかったりするので時々困る。

class Something
{
public:
	max(); //←メンバ関数の宣言だがマクロで勝手に置き換えられる
};

まあ自作クラスなら名前を変えたらいいだけなので何とかなるが標準クラスであるnumelic_limitsとかでぶつかられたりするものだから困り者である。全くmicrosoftはなんでこんなマクロを作ったんだろうかと思うのだが、おそらくSTLより歴史が古いせいで後からSTLの方がぶつかったのだろうから仕方ないと言えば仕方ないのだがもうちょっと先を見て欲しかったかなぁと後出しじゃんけんしてみる。ひょっとしたらANSI側からmicrosoftへの嫌がらせではないかとちょっと邪推してみたり・・・。

まあとにかく、ぶつかっているものは仕方ないのでうまく使いこなすことを考えるのだがMicrosoft側も回避策を一応用意しており、事前にNOMINMAXを定義してやればマクロは定義されない。

#define NOMINMAX
#include <windows.h>

 ・・・

const int c = std::max( a, b );//←問題なく使える。

ただしwindowsアプリが前提ならいいが、汎用ライブラリだとNOMINMAXとか定義されているのはなんとなく美しくない(謎)。そんなわけで他の解決策をあげるとこんなのがある。

const int c = (std::max)( a, b );//←マクロが発動しない

括弧で囲ってしまうことによりマクロをつぶすのである。これで何とかなるのだがなんとなく不恰好(^^;なのだが私はいつもこのスタイルで書いている。
最近知ったのだがもう一つ方法がある。明示的にテンプレート引数を渡せばよいのだ。

const int c = std::max< int >( a, b );//←マクロが発動しない

これでもうまくいく。うーん、前者とどちらがキレイかなぁ・・・(^^; なかなか悩ましいところである。


ついでに・・・もっとメタメタしたい場合。

template< int A, int B >
class Greater{
	template< bool b > class Sub;
	template<> class Sub< true >{ public: enum{ c = A }; };
	template<> class Sub< false >{ public: enum{ c = B }; };
public:
	enum{ c = Sub< (A>B) >::c };
};

const int c = Greater< 10, 100 >::c;

もちろんネタですが。