SFINAE(substitution failure is not an error)

あまり日本語資料のないテクニック...というか仕組み


直訳すると「置き換え失敗はエラーじゃない」...ダサイ


テンプレートの置き換えに失敗してもエラーにならないようにする

template <class Container>
void foo(typename Container::iterator* = 0)
{
    cout << "コンテナ" << endl;
}

template <class>
void foo(...)
{
    cout << "コンテナじゃない" << endl;
}


int main()
{
    foo<vector<int> >(); // コンテナ
    foo<int>();          // コンテナじゃない

    return 0;
}

BOOST_FOREACHで、引数が配列かコンテナか判断するのに使われていたりする

struct sfinae_types {
    typedef char yes;
    typedef struct { char arr[2]; } no;
};

template <class Type>
struct is_stl : sfinae_types {
private:
    template <class Type>
    static yes check(typename Type::iterator*);

    template<class>
    static no check(...);
public:
    enum { value = sizeof(yes)==sizeof(check<Type>(0)) };
};


// enable_if
template <bool, class Type = void>
struct enable_if_c {
    typedef Type type;
};

template <class Type>
struct enable_if_c<false, Type> {};

template <class Cond, class Type = void>
struct enable_if : public enable_if_c<Cond::value, Type> {};
// 配列
template <class Type, int Size>
Type* begin(Type (&ar)[Size], void* = 0)
{
    return ar;
}

// コンテナ
template <class Container>
typename Container::iterator begin(Container& container, typename enable_if<is_stl<Container> >::type* = 0)
{
    return container.begin();
}

↑このテクニックは『Modern C++ Design』で紹介されている



SFINAEを実装しているコンパイラは少ないらしい
Visual C++では8.0(2005)以降