SFINAE(Substitution Failure Is Not An Error)のメモ

関数のオーバーロードを使用する際に、うまくコンパイルできないケースをエラーとするのではなく、オーバーロードの対象から自ずと外してしまうという技法((技法というよりもコンパイラとしてこのような動作となるか否かって話っぽい))。以下の例の場合はtestとintでテンプレート引数を指定した際にはT::typeと引数を指定したケースが自ずとオーバーロード対象からはずれ、他方のtest関数がマッチングされエラーとはならない(代入エラーとはそれ自身はエラーではないというSFINAE原義)。

#include <iostream>
//適当なクラス
struct Hoge{typedef int type;};
//TとT::type型をそれぞれ引数とするtest関数
template<typename T>
void test(T){std::cout << "T" << std::endl;}
template<typename T>
void test(typename T::type){std::cout << "T::type" << std::endl;}

int main()
{
    test<Hoge>(0); //上(T::type)が呼ばれる
    test<int>(0);  //上(T)が呼ばれる
    return 0;
}

実行結果

T::type
T

Boost enable_ifのページにあった例

似たような例として参考にLINKを張ってあるBoostのenable_ifの例が良かったので、それを引用させていただく。以下のコードではnegate関数を二つ定義しているものの、templateを使って書いている方はint型に対してインスタンス化されないので、除去される(エラーにはならずただ除去される!)。

#include <iostream>
//二つのnegate関数(下の関数はインスタンス化されない)
int negate(int i) { return -i; }
template <class F>
typename F::result_type negate(const F& f) { return -f(); }

int main()
{
    int a = 10;
    int x = negate(a);
    return 0;
}

enable_ifを使ってやる

C++11から標準ライブラリ入りしたenable_ifを使ってSFINAEを作り出すのが常套手段。ただしここでenable_if関数は手元のVS2008にはない&勉強兼ねて自作した。
普通にdouble型とint型の

#include <iostream>
//自作is_int, is_double
template<class T>
struct is_int{static const bool value = false;};
template<>
struct is_int<int>{static const bool value = true;};
template<class T>
struct is_double{static const bool value = false;};
template<>
struct is_double<double>{static const bool value = true;};
//enable_if
template<bool Cond, class T = void>
struct enable_if{};
template<class T>
struct enable_if<true, T> { typedef T type; };
//
//
template<class T>
typename enable_if<is_int<T>::value, T>::type hoge(T t) 
{
    std::cout << "hoge: int\n";
    return t;
} 
template<class T>
typename enable_if<is_double<T>::value, T>::type hoge(T t) 
{
    std::cout << "hoge: double\n";
    return t;
}
 
int main()
{
    hoge(1.2);
    hoge(10);
    return 0;
}

参考
Substitution failure is not an error - Wikipedia
enable_if - 1.53.0(1.2のBackgroundの箇所に記載あり)
std::enable_if - cppreference.com