
#include <iostream>
#include <cassert>

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 P0, class P1, class P2, class P3, class P4>
struct stackinstance : stackelement {
protected:
	const char* name;
	P0& p0;
	P1& p1;
	P2& p2;
	P3& p3;
	P4& p4;
public:
	template<int N>
	stackinstance(const char(&name_)[N], P0& p0_, P1& p1_, P2& p2_, P3& p3_, P4& p4_)
		:name(name_), p0(p0_), p1(p1_), p2(p2_), p3(p3_), p4(p4_) {}
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 << p0
				<< between_params << p1
				<< between_params << p2
				<< between_params << p3
				<< between_params << p4
				<< after_params; }
};

template<class P0, class P1, class P2, class P3>
struct stackinstance<P0, P1, P2, P3, void> : stackelement {
protected:
	const char* name;
	P0& p0;
	P1& p1;
	P2& p2;
	P3& p3;
public:
	template<int N>
	stackinstance(const char(&name_)[N], P0& p0_, P1& p1_, P2& p2_, P3& p3_)
		:name(name_), p0(p0_), p1(p1_), p2(p2_), p3(p3_) {}
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 << p0
				<< between_params << p1
				<< between_params << p2
				<< between_params << p3
				<< after_params; }
};

template<class P0, class P1, class P2>
struct stackinstance<P0, P1, P2, void, void> : stackelement {
protected:
	const char* name;
	P0& p0;
	P1& p1;
	P2& p2;
public:
	template<int N>
	stackinstance(const char(&name_)[N], P0& p0_, P1& p1_, P2& p2_)
		:name(name_), p0(p0_), p1(p1_), p2(p2_) {}
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 << p0
				<< between_params << p1
				<< between_params << p2
				<< after_params; }
};

template<class P0, class P1>
struct stackinstance<P0, P1, void, void, void> : stackelement {
protected:
	const char* name;
	P0& p0;
	P1& p1;
public:
	template<int N>
	stackinstance(const char(&name_)[N], P0& p0_, P1& p1_)
		:name(name_), p0(p0_), p1(p1_) {}
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 << p0 
				<< between_params << p1
				<< after_params; }
};

template<class P0>
struct stackinstance<P0, void, void, void, void> : stackelement {
protected:
	const char* name;
	P0& p0;
public:
	template<int N>
	stackinstance(const char(&name_)[N], P0& p0_)
		:name(name_), p0(p0_) {}
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 << p0
				<< after_params; }
};

template<>
struct stackinstance<void, void, void, void, void> : stackelement {
protected:
	const char* name;
public:
	template<int N>
	stackinstance(const char(&name_)[N])
		:name(name_) {}
protected:
	virtual const char* get_name() const {return name;}
	virtual void printparams(std::ostream&,
									  const char*,
									  const char*,
									  const char*) const 
	{}
};

template<int N, class P0, class P1, class P2, class P3, class P4>
stackinstance<P0, P1, P2, P3, P4> StackTrace(const char(&name_)[N], P0& p0_, P1& p1_, P2& p2_, P3& p3_, P4& p4_)
{return stackinstance<P0, P1, P2, P3, P4>(name_, p0_, p1_, p2_, p3_, p4_);}

template<int N, class P0, class P1, class P2, class P3>
stackinstance<P0, P1, P2, P3, void> StackTrace(const char(&name_)[N], P0& p0_, P1& p1_, P2& p2_, P3& p3_)
{return stackinstance<P0, P1, P2, P3, void>(name_, p0_, p1_, p2_, p3_);}

template<int N, class P0, class P1, class P2>
stackinstance<P0, P1, P2, void, void> StackTrace(const char(&name_)[N], P0& p0_, P1& p1_, P2& p2_)
{return stackinstance<P0, P1, P2, void, void>(name_, p0_, p1_, p2_);}

template<int N, class P0, class P1>
stackinstance<P0, P1, void, void, void> StackTrace(const char(&name_)[N], P0& p0_, P1& p1_)
{return stackinstance<P0, P1, void, void, void>(name_, p0_, p1_);}

template<int N, class P0>
stackinstance<P0, void, void, void, void> StackTrace(const char(&name_)[N], P0& p0_)
{return stackinstance<P0, void, void, void, void>(name_, p0_);}

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

#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 main(int argc, char** argv) {
	auto trace = StackTrace(__FUNCSIG__, argc, argv);
	try {
		Foo();
	} catch(const stack_aware_exception& exc) {
		std::cout << exc.what();
	}
	return 0;
}