tags:

views:

59

answers:

1

I have the following piece of code:

class ICookable
{
public:
    virtual void CookMe () = 0;
    virtual ~ICookable () {};
};

class Egg : public ICookable
{
public:
    virtual void CookMe () {cout << "Egg cooked!" << endl;}
};

template <class T>
void Cook (T&)
{
    cout << "Item Uncookable!" << endl;
}

template <>
void Cook (ICookable& c)
{
    c.CookMe ();
}

int _tmain(int argc, _TCHAR* argv[])
{
    Egg egg;
    Cook (egg);
    return 0;
}

I want the Cook function to behave differently depending on whether its parameter is inherited from ICookable interface or not. However in the example above I get "Item Uncookable" message for Egg parameter, unless I manually write:

Cook<ICookable> (egg);

Is there a way to let the compiler automatically choose the right realization for ICookable descendants?

+3  A: 

Compile-time dispatch through boost::is_base_of and class template partial specialization:

template<class T, class _>
struct CookDetail {
  static void cook(T& obj) {
    cout << "uncookable\n";
  }
};
template<class T>
struct CookDetail<T, boost::true_type> {
  static void cook(ICookable& obj) {
    obj.CookMe();
  }
};

template<class T>
void cook(T& obj) {
  return CookDetail<T, boost::is_base_of<ICookable, T> >::cook(obj);
}

However, having cook(non_icookable_obj) "work" is an error to me. I'd prefer the compile-time error for trying to cook a non-cookable.

Note that what you tried fails because that's just how function resolution works. An exact match through a template (cook<Egg>(Egg&)) is considered better than one which requires a conversion (cook(ICookable&)). Details are in the FCD if you want the arcane technicalities.

Roger Pate