Substitution Failure Is Not An Error, or more compactly, SFINAE
But in your particular case, you don't need SFINAE, virtual members, or anything fancy like that.
You just need an ordinary overloaded function.
int GetInt(A& t) { return t.GetInt(); }
int GetInt(const B& t) { return t.m; }
If there's code that needs to be shared between the different versions, refactor it so that there's a template that calls an overloaded inline function, all type-specific behavior is in the inline function, and all shared behavior is in the template.
For your "I have many many classes" need, SFINAE would look more or less like this:
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;
}
EDIT: The reality of SFINAE is much uglier, at least until C++0x comes around. In fact it starts looking just as bad as GMan's answer.
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);
}