Skip to content

Instantly share code, notes, and snippets.

@bisqwit
Last active July 12, 2019 01:18
Show Gist options
  • Save bisqwit/5c2906475844c3c465ad9dcee6d45439 to your computer and use it in GitHub Desktop.
Save bisqwit/5c2906475844c3c465ad9dcee6d45439 to your computer and use it in GitHub Desktop.
Recursion exercise (C++17)
#include <utility>
/* https://godbolt.org/z/9ic5bL
A child couldn’t sleep, so her mother told a story about a little frog,
who couldn’t sleep, so the little frog’s mother told a story about a little bear,
who couldn’t sleep, so the little bear’s mother told a story about a little weasel
— who fell asleep;
… and the little bear fell asleep;
… and the little frog fell asleep;
… and the child fell asleep.
Interestingly, the disassembly shows that the compiler was completely able to remove any signs of recursion from the code.
*/
template<typename R, typename... A>
struct callerbase
{
virtual R operator() (A... args) = 0;
};
template<typename F, typename R, typename... A>
struct caller: public callerbase<R, A...>
{
using base_t = callerbase<R, A...>;
F func;
caller(F f): func(std::forward<F>(f)) {}
virtual R operator() (A... args) { return func(*this, std::forward<A>(args)...); }
};
template<typename F, typename... A>
auto recursively(F&& f, A&&... xs)
{
using R = std::invoke_result_t<F, callerbase<void, A...>, A...>;
return f( (typename caller<F, R, A...>::base_t&&) caller<F, R, A...>(std::forward<F>(f)),
std::forward<A>(xs)... );
}
#if 1 /* libfmt */
#include <iostream>
#include <fmt/format.h>
#include <string_view>
using namespace std::literals;
using namespace fmt::literals;
int main()
{
std::initializer_list<const char*> animals{"little frog","little bear","little weasel"};
std::cout << recursively(
[&](auto&& caller,
std::string_view who, const char* who2,
std::string_view gen, auto begin, auto end, std::size_t pad) -> std::string
{
return "{}{} fell asleep"_format(who, (begin==end)
? ""s
: " couldn’t sleep, so {} mother told a story about a {}{};\n{:{}s}… and the {}"_format(
gen,*begin,
caller(",\n{:{}s} who"_format(""sv,pad), *begin,
"the {}’s"_format(*begin),
std::next(begin), end, pad+2),
""sv,pad, who2));
},
"A child"sv, (const char*)"child", "her"sv, animals.begin(), animals.end(), 0) << ".\n";
}
#else /* no libfmt */
/*https://godbolt.org/z/PXUHKr*/
#include <iostream>
#include <string_view>
using namespace std::literals;
int main()
{
std::initializer_list<const char*> animals{"little frog","little bear","little weasel"};
recursively(
[&](auto&& caller, std::size_t pad,
std::string_view who, std::string_view who2,
std::string_view gen, auto begin, auto end)
{
std::cout << who;
if(begin != end)
{
std::cout << " couldn’t sleep, so " << gen
<< " mother told a story about a " << *begin;
caller(pad+2,
",\n" + std::string(pad,' ') + " who", *begin,
"the "s + *begin + "’s", std::next(begin), std::move(end));
std::cout << ";\n" << std::string(pad,' ') << "… and the " << who2;
}
std::cout << " fell asleep";
},
0, "A child"sv, "child"sv, "her"sv, animals.begin(), animals.end());
std::cout << ".\n";
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment