あまり日本語資料のないテクニック...というか仕組み
直訳すると「置き換え失敗はエラーじゃない」...ダサイ
テンプレートの置き換えに失敗してもエラーにならないようにする
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)以降