#include <type_traits>
#include <string>
 
 
std::string fooImpl(int i) { return "int!"; }
 
template <typename T>
void fooImpl(T);
 
template <typename T>
using HasFooImpl = typename std::is_same<std::string, decltype(fooImpl(std::declval<T>()))>;
 
template <typename T>
typename std::enable_if<HasFooImpl<T>::value, std::string>::type 
foo(T&& t)
{
  return fooImpl(std::forward<T>(t));
}
 
template <typename T>
typename std::enable_if<!HasFooImpl<T>::value, std::string>::type
foo(T&& t)
{
    return "generic!";
}
 
struct X{};
 
template <class T>
struct S{};
template <class T>
std::string fooImpl(S<T> const&) { return "S<T>"; }
 
#include <iostream>
int main()
{
  std::cout << foo(1) << '\n';
  std::cout << foo("nope") << '\n';
  std::cout << foo(S<unsigned>{}) << '\n';
  std::cout << foo(X{}) << '\n';
  std::cout << foo(3.4) << '\n';  //will call fooImpl(int)
}