
#include <iostream>
#include <cassert>
#include <tuple>

//Indecies Trick
template <std::size_t... Is>
struct indices {};

template <std::size_t N, std::size_t... Is>
struct build_indices
  : build_indices<N-1, N-1, Is...> {};

template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};

template <typename Tuple>
using IndicesFor = build_indices<std::tuple_size<Tuple>::value>;
    
    
    
    

class stackelement {
	stackelement* caller;
	stackelement* callee;
	static stackelement*& frameptr() 
	{
		static stackelement* frameptr=NULL;
		return frameptr;
	}
protected:
	virtual const char* get_name() const =0;
	virtual void printparams(std::ostream& out,
									  const char* before_params,
									  const char* between_params,
									  const char* after_params) const =0;
public:
	stackelement() 
		: caller(frameptr()), callee(NULL)
	{ frameptr() = this;}
	stackelement(const stackelement& r) 
		: caller(r.caller), callee(r.callee) 
	{
		assert(frameptr() == &r);
		frameptr() = this;
	}
	stackelement& operator=(const stackelement& r)  {
		assert(frameptr() == &r);
		caller = r.caller;
		callee = r.callee;
		frameptr() = this;
		return *this;
	}
	virtual ~stackelement() {
		if (caller)
			caller->callee = NULL;
		frameptr() = caller;
	}
	static void print(std::ostream& out, 
						const char* begin_line="", 
						const char* before_params=" with ", 
						const char* between_params=", ",
						const char* after_params=".",
						const char* end_line="\n") {
		stackelement* self = frameptr();
		do {
			out << begin_line << self->get_name();
			self->printparams(out, before_params, between_params, after_params);
			out << end_line;
			self = self->caller;
		} while(self);
	}
};

template<class first, class...Ps, std::size_t... Is>
std::ostream& _print_tup(std::ostream& out, const std::tuple<first, Ps...>& tup, const char*sep, indices<Is...>)
{
	using for_each = int[];
	out << std::get<0>(tup);
	if (sizeof...(Ps))
		for_each{(out<<sep<<std::get<Is+1>(tup),0)...,0};
	return out;
}

template<class first, class...Rest>
std::ostream& print_tup(std::ostream& out, const std::tuple<first, Rest...>& tup, const char*sep)
{return _print_tup(out,tup,sep,build_indices<sizeof...(Rest)>{});}
template<class first>
std::ostream& print_tup(std::ostream& out, const std::tuple<first>& tup, const char*sep)
{return out << std::get<0>(tup);}
std::ostream& print_tup(std::ostream& out, const std::tuple<>& tup, const char*sep)
{return out;}

template<class...Ps>
struct stackinstance : stackelement {
protected:
	const char* name;
	std::tuple<Ps&...> ps;
public:
	template<int N>
	stackinstance(const char(&name_)[N], Ps&...Vs)
		:name(name_), ps(Vs...) {}
protected:
	virtual const char* get_name() const  {return name;}
	virtual void printparams(std::ostream& out,
									  const char* before_params,
									  const char* between_params,
									  const char* after_params) const 
	{
		out<<before_params;
		print_tup(out,ps,between_params);
		out<<after_params;
	}
};

template<int N, class...Ps>
stackinstance<Ps...> StackTrace(const char(&name_)[N], Ps&...Vs)
{return stackinstance<Ps...>(name_, Vs...);}

#ifdef __GNUC__
#define __FUNCSIG__ __PRETTY_FUNCTION__
#endif













#include <iostream>
#include <sstream>
#include <exception>
#include <stdexcept>

class stack_aware_exception : public std::runtime_error {
	std::string get_stack() {
		std::stringstream stacktrace;
		stackelement::print(stacktrace);
		return stacktrace.str();
	}
public:
	stack_aware_exception() :std::runtime_error(get_stack()) {}
};

unsigned thing(unsigned i) {
	auto trace = StackTrace(__FUNCSIG__, i);
	if (i==10)
		throw stack_aware_exception();
	else if (i==0)
		return i;
	return thing(i-1);
}

int Foo() {
	auto trace = StackTrace(__FUNCSIG__);
	return thing(7) + thing(0) + thing(17);
}

int Params(int a, std::string s, void* c)
{
	auto trace = StackTrace(__FUNCSIG__, a, s, c);
	return Foo();
}

int main(int argc, char** argv) {
	auto trace = StackTrace(__FUNCSIG__, argc, argv);
	try {
		Params(3, "HI", nullptr);
	} catch(const stack_aware_exception& exc) {
		std::cout << exc.what();
	}
	return 0;
}