#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;
}