Example
#include <stacktrace>
#include <iostream>
int foo() {
std::cout << std::stacktrace::current();
return {};
}
int main() {
return foo();
}
0# foo() at /app/example.cpp:5
1# main() at /app/example.cpp:10
Puzzle
- Can you implement
call
function which will call itself recursively N times and then it wil go through the stack and count how many calls has happend until the call at given source line (from)?
#include <stacktrace>
template<auto N>
[[nodiscard]] auto call(auto from);
int main() {
using namespace boost::ut;
"stacktrace"_test = [] {
expect(1_u == call<0>(__LINE__));
expect(3_u == call<2>(__LINE__));
expect(4_u == call<3>(__LINE__));
};
}
Solutions
template <auto N>
[[nodiscard]] auto call(auto from)
{
if constexpr (N == 0)
{
return 1;
}
else
{
return call<N-1>(from) + 1;
}
}
template <auto N>
[[nodiscard]] auto call(auto from)
{
if constexpr (N > 0)
{
return call<N-1>(from) + 1;
}
else
{
const auto st = std::stacktrace::current();
return std::ranges::any_of(st, [from](const auto & s) {
return from == s.source_line();
});
}
}
template <auto N>
[[nodiscard]] auto call(auto from) {
if constexpr (N == 0) {
const auto st = std::stacktrace::current();
const auto it = std::find_if(std::begin(st), std::end(st),
[&] (const auto& entry) { return entry.source_line() == from; });
return std::distance(std::begin(st), it);
} else {
return call<N-1>(from);
}
}
template<auto N>
[[nodiscard]] auto call(auto from) {
if constexpr(N > 0) {
return call<N-1>(from);
}
auto st = std::stacktrace::current();
const auto first_empty = std::find_if(st.begin(), st.end(), [](auto&& trace) {
return trace.description().empty();
});
return std::distance(st.begin(), first_empty);
}
template<auto N>
[[nodiscard]] auto call(auto from)
{
if constexpr(N ==0)
{
auto bt = std::stacktrace::current();
return std::distance ( bt.begin()
, std::find_if( bt.begin()
, bt.end()
, [from](auto&& entry){ return entry.source_line() == from;}
)
);
} else
return call<N-1>(from);
}
template <auto N>
[[nodiscard]] auto call(auto from) {
if constexpr (N == 0) {
const auto &st = std::stacktrace::current();
const auto it = std::find_if(
std::cbegin(st), std::cend(st),
[=](const auto &entry) { return entry.source_line() == from; });
return std::distance(std::cbegin(st), it);
} else {
return call<N - 1>(from);
}
}
template<auto N>
[[nodiscard]] auto call(auto from){
if constexpr(N == 0){
const auto& stacktrace = std::stacktrace::current();
const auto it = std::ranges::find_if(stacktrace,
[from](const auto& entry){ return entry.source_line() == from; });
return std::distance(std::cbegin(stacktrace), it);
}
else{
return call<N-1>(from);
}
}
template<auto N>
[[nodiscard]] auto call(auto from) {
if constexpr (N == 0) {
const auto& st = std::stacktrace::current();
auto last = std::find_if(st.begin(), st.end(), [from](auto&& it){
return it.source_line() == from;
});
return std::distance(st.begin(), last);
}
else {
return call<N - 1>(from);
}
};
template<auto N>
[[nodiscard]] auto call(auto from) requires (N>=0) {
if constexpr (N == 0)
{
auto cnt = 0;
for( auto frame : std::stacktrace::current() )
{
if (to_string(frame).contains(__FUNCTION__)) {
cnt++;
}
}
return cnt;
}
else
{
return call<N-1>(from);
}
};
template<auto N>
[[nodiscard]] auto call(auto from) {
if constexpr(N>0)
return call<N-1>(from);
else {
int n = 0;
std::basic_stacktrace st = std::stacktrace::current();
for(auto it = st.begin(); it < st.end(); it++)
if (it->description().starts_with("auto call"))
n++;
return n;
}
}
template<auto N>
[[nodiscard]] auto call(auto from){
if constexpr (N < 1){
auto s = std::stacktrace().current();
auto entry = std::find_if(s.begin(),s.end(), [from](auto e){ return e.source_line() == from;});
return (entry-s.begin());
}
else{
return call<N-1>(from);
}
}