#include <type_traits>
#include <functional>
#include <iostream>
#include <cstdlib>

template <class Functor, class... Args>
void run_helper(std::false_type, Functor f, Args&&... args)
{
    f(std::forward<Args>(args)...);
}

template <class Functor, class Arg0, class... Args>
void run_helper(std::true_type, Functor f, Arg0&& arg0, Args&&... args)
{
    (std::forward<Arg0>(arg0).*f)(std::forward<Args>(args)...);
}

template <class Functor, class... Args>
void run(Functor f, Args&&... args)
{
    run_helper(typename std::is_member_pointer<Functor>::type(),
               f, std::forward<Args>(args)...);
}

void freeFunction(int n) { std::cout << n << "\n"; }

struct Foo
{
	void memberFunction(int n) { std::cout << n << "\n"; }
};

struct Bar
{
	void overloadedMemberFunction(int n) { std::cout << n << "\n"; }
	void overloadedMemberFunction(long n) { std::abort(); }
};

struct Baz
{
	template <class T>
	void templateMemberFunction(T n) { std::cout << n << "\n"; }
};

int main() {
	run(freeFunction, 1111);
	
	auto lambda = [](int n){ std::cout << n << "\n"; };
	run(lambda, 2222);
	
	Foo foo;
	run(&Foo::memberFunction, foo, 3333);
	
	Bar bar;
	run<void(Bar::*)(int)>(&Bar::overloadedMemberFunction, bar, 4444);
	
	Baz baz;
	run<void(Baz::*)(int)>(&Baz::templateMemberFunction, baz, 5555);
}