Last active
July 12, 2019 01:18
-
-
Save bisqwit/5c2906475844c3c465ad9dcee6d45439 to your computer and use it in GitHub Desktop.
Recursion exercise (C++17)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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