#include <iostream>
#include <tuple>
#include <functional>
#include <string>
using namespace std;

template <size_t N>
struct apply_tuple_func
{
    template<typename F, typename T, typename... A>
    static inline auto apply(F&& f, T&& t, A&&... a) -> 
    	decltype(
    		apply_tuple_func<N-1>::apply(
    			std::forward<F>(f), 
    			std::forward<T>(t), 
    			std::get<N-1>(std::forward<T>(t)), 
    			std::forward<A>(a)...))
    {
        return apply_tuple_func<N-1>::apply(
        	std::forward<F>(f), 
        	std::forward<T>(t), 
        	std::get<N-1>(std::forward<T>(t)), 
        	std::forward<A>(a)...);
    }
};

template <>
struct apply_tuple_func<0>
{
    template<typename F, typename T, typename... A>
    static inline auto apply(F&& f, T&&, A&&... a) -> 
    	decltype(
    		std::forward<F>(f)(std::forward<A>(a)...))
    {
        return std::forward<F>(f)(std::forward<A>(a)...);
    }
};

template <typename F, typename T>
inline auto apply_tuple(F&& f, T&& t) -> 
	decltype(
		apply_tuple_func<
				std::tuple_size<typename std::decay<T>::type>::value>
		::apply(
			std::forward<F>(f),
			std::forward<T>(t)))
{
    return apply_tuple_func<
    		std::tuple_size<typename std::decay<T>::type>::value>
    	::apply(std::forward<F>(f), std::forward<T>(t));
}

/*

	FUN STUFF BELOW:
	
	This will only run one specific function type,
	but you could do stuff through other fun means to make it run other things

*/

template<typename R, typename... A>
R test(const std::function<R(A...)>& func)
{
	std::tuple<int, float, string> a(5, 2.3, "Some text");
	return apply_tuple(func, a);
}

void test2(int i, float f, string s)
{
	cout << i << " " << f << " " << s << endl;
}

int main() {
	test(std::function<void(int, float, string)>([](int i, float f, string s)
		{
			cout << i << " " << f << " " << s << endl;
		}));
	test(std::function<void(int, float, string)>(&test2));
	return 0;
}