置換の失敗はエラーではありません。よりコンパクトに言えば、SFINAEです。
ただし、特定のケースでは、SFINAE、仮想メンバー、またはそのような派手なものは必要ありません。
通常のオーバーロードされた関数が必要です。
int GetInt(A& t) { return t.GetInt(); }
int GetInt(const B& t) { return t.m; }
異なるバージョン間で共有する必要のあるコードがある場合は、オーバーロードされたインライン関数を呼び出すテンプレートがあり、すべてのタイプ固有の動作がインライン関数にあり、すべての共有動作がテンプレートにあるように、コードをリファクタリングします。
「私には多くのクラスがあります」というニーズに対して、SFINAEは多かれ少なかれ次のようになります。
template<typename T>
int GetInt(const T& t, int (T::*extra)() const = &T::GetInt)
{
return t.GetInt();
}
template<typename T>
auto GetInt(const T& t) -> decltype(t.m)
{
return t.m;
}
編集:SFINAEの現実は、少なくともC ++ 0xが登場するまでは、はるかに醜いものです。実際、それはGManの答えと同じくらい悪く見え始めます。
struct A{ int GetInt() const { return 10; } };
struct B{ int m; };
template<typename T, int (T::*extra)() const>
struct has_mfunc
{
typedef int type;
};
template<typename T>
typename has_mfunc<T, &T::GetInt>::type GetInt(const T& t)
{
return t.GetInt();
}
template<typename T, typename U, U (T::*extra)>
struct has_field
{
typedef U type;
};
template<typename T>
typename has_field<T, int, &T::m>::type GetInt(const T& t)
{
return t.m;
}
int main(void)
{
A a;
B b;
b.m = 5;
return GetInt(a) + GetInt(b);
}