#include <cassert>

template<typename T1, typename T2>
  struct is_same
{
  static const bool value = false;
};

template<typename T>
  struct is_same<T,T>
{
  static const bool value = true;
};

template<typename F, typename Arg1>
  struct parameter_type
{
  // what goes here?
};

struct takes_int
{
  void operator()(int);
};

struct takes_float_ref
{
  char operator()(float &);
};

struct takes_float_cref
{
  int operator()(const float &);
};

struct bar {};

struct something_convertible_to_bar
{
  operator bar ();
};

struct takes_bar
{
  bar operator()(bar);
};

struct takes_value
{
  template<typename T> void operator()(T);
};

struct has_overloads
{
  bar operator()(int &);

  void operator()(const int &);
};

int main()
{
  // int
  assert((is_same<
           parameter_type<takes_int, unsigned int>::type,
           int
         >::value));

  // float &
  assert((is_same<
           parameter_type<takes_float_ref, float>::type,
           float &
         >::value));

  // const float &
  assert((is_same<
           parameter_type<takes_float_cref, int>::type,
           const float &
         >::value));

  // bar
  assert((is_same<
           parameter_type<takes_bar, something_convertible_to_bar>::type,
           bar
         >::value));

  // int
  assert((is_same<
           parameter_type<takes_value, int &>::type,
           int
         >::value));

  // const int &
  assert((is_same<
           parameter_type<has_overloads, const int &>::type,
           const int &
         >::value));

  return 0;
}

