SFINAE で遊んでみた 1/2

```cpp:
#include <stdio.h>
#include <vector>
#include <map>
using namespace std;

// 準備中です...
int main() { return 0; }
struct Out {
  Out() {}
  Out(const Out& out) { puts(""); }
  Out& operator|(const char* mes) { puts(mes); return *this; }
  Out& operator|(int n) { printf("# %d  // ", n); return *this; }
};
template<int> struct Holder { static Out out; };
#define O template<> Out Holder<__LINE__>::out = Out()
#define V(...) __VA_ARGS__ | #__VA_ARGS__

O | "C++ の SFINAE という仕様を利用したトリックが"
  | "思った以上にパワフルだったので遊んでみました．";

O | "SFINAE とは，特定条件下でテンプレート置き換えの結果がエラーになっても，"
  | "それをコンパイルエラーとせず，単にそのテンプレートを無視するという"
  | "C++ の特徴です．";

O | "特定の型引数でエラーになるようなテンプレート A を書いても"
  | "SFINAE によって，コンパイルエラーにならず別のテンプレート B に"
  | "フォールバックさせることができるので，"
  | "エラーの有無で A B を切り替えるような挙動がコンパイル時に可能です．";

O | "★ SFINAE を使わない判定器";

O | "まず，value 定数を持つ2つの型を用意します．";

struct true_v {
  enum { value = 1 };
};

struct false_v {
  enum { value = 0 };
};

O | "次に is_void テンプレートを用意します．"
  | "デフォルトの実装では false_v を継承します．";

template <class T>
struct is_void : public false_v {};

O | "false_v を継承しているので，is_void<XXX>::value は 0 ですね．"
  | "確認してみましょう";

O | V(is_void<double>::value);

O | "is_void はテンプレートなので"
  | "特定のテンプレート引数に対して特殊化できます．"
  | "つまり…";

template <>
struct is_void<void> : public true_v {};

O | "特殊化することで与えられた型引数が void の時だけ true_v を継承し，"
  | "value が 1 を返すような判定器になりました．"
  | "確認してみましょう．";

O | V(is_void<char>::value)
  | V(is_void<long>::value)
  | V(is_void<void>::value);

O | "これは普通のテンプレート特殊化で，SFINAE は使っていません．";

O | "★ SFINAE を使う判定器";

O | "次は有名な STL コンテナ型の判定器を作ってみます．"
  | "この判定器はある型 T が T::iterator を持つか否かで"
  | "その型が STL コンテナであるか否かを判定します．"
  | "実際には型 T が STL コンテナであるためには，"
  | "もっと厳しい条件がつくそうなので，これは簡易判定器です．";

O | "先ほどと同じように特殊化前のテンプレートを false_v を継承して用意します．";

template <class T, class X=void>
struct is_stl : public false_v {};

O | "is_void と異なり is の型引数に X が加わわっています．"
  | "特殊化する時に，この X に T::iterator を含むか否かを"
  | "コンパイラに判断させる式をあてます．";

O | "次にヘルパーテンプレートを用意します．";

template <class>
struct ignore {
  typedef void type;
};

O | "このテンプレートは次のように type を参照するために使います．"
  | "テンプレート引数が宣言内でまったく使われていないので，"
  | "どんな引数を渡しても type は void になります．"
  | "引数を無視するという意味で ignore と名づけました．"
  | "本当に void になっているのか，先ほどの is_void で"
  | "確認してみましょう．";

O | V(is_void< ignore<void>::type >::value)
  | V(is_void< ignore<int>::type >::value)
  | V(is_void< ignore< vector<int> >::type >::value);

O | "どうやらきちんと，void になっているようです．"
  | "最後にこのヘルパーテンプレートを使って， is_stl を特殊化します．";

template <class T>
struct is_stl<T, typename ignore<typename T::iterator>::type> :
    public true_v {};

O | "第一引数はテンプレート T がそのままあてられていて特殊化されていません．"
  | "第二引数は ignore<XXX>::type があてられているのでコイツは void です．"
  | "つまりこの特殊化は，第二引数が void である場合に適用される"
  | "ということになります．";

O | V(is_stl< vector<int>, int >::value)
  | V(is_stl< vector<int>, void >::value)
  | V(is_stl< map<int, int>, void >::value);

O | "また第二引数のデフォルトは void なので省略した場合も特殊化が行われます．";

O | V(is_stl< vector<int> >::value)
  | V(is_stl< map<int, int> >::value);

O | "では 第一引数はなんでも良いのかというとそうではなく"
  | "テンプレートの特殊化で T::iterator という記述がされているので"
  | "iterator が存在しないような型，"
  | "例えば int が T として渡されると，int::iterator エラーになります．"
  | "T::iterator は ignore テンプレートによって無視されてしまう部分ですが，"
  | "コンパイラはきちんと解釈を行なっているのです．";

O | "ここでようやく SFINAE の登場です．"
  | "通常 int::iterator など存在しない識別子を参照した場合，"
  | "これはコンパイラエラーになってしまいます．";

O | "しかしテンプレートの置き換えによって生じた今回のエラーは話が別で，"
  | "SFINAE によってコンパイルエラーとしては扱われず，単にこの特殊化が"
  | "無視されるだけですみます．";

O | "結果として T が iterator を持たない場合は特殊化の宣言がなくなり，"
  | "元の宣言が使われることになります．";

O | V(is_stl< vector<int> >::value)
  | V(is_stl< map<int, int> >::value)
  | V(is_stl< int >::value)
  | V(is_stl< double >::value);

O | "実はこのテンプレートは第二引数を常に省略して使うので，"
  | "T::iterator がエラーになるかどうかが，特殊化の成否を分けます．"
  | "STL コンテナ判定器．完成．";
```