Skip to content

Instantly share code, notes, and snippets.

@ecatmur
Last active June 11, 2020 13:16
Show Gist options
  • Save ecatmur/465e616c7fc1b7122790d1c2d4b5ca29 to your computer and use it in GitHub Desktop.
Save ecatmur/465e616c7fc1b7122790d1c2d4b5ca29 to your computer and use it in GitHub Desktop.
Hardened Y combinator that handles recursive return type deduction via [dcl.spec.auto]/10
#include <utility>
#include <type_traits>
template <class F>
struct fix_t {
template <class Ff>
struct ref {
Ff ff;
template <class... Args>
constexpr decltype(auto) operator()(Args&&... args) const {
return static_cast<Ff>(ff)(ref{static_cast<Ff>(ff)}, std::forward<Args>(args)...);
}
};
F f;
template <class... Args>
constexpr decltype(auto) operator()(Args&&... args) const& {
return f(ref<F const&>{f}, std::forward<Args>(args)...);
}
template <class... Args>
constexpr decltype(auto) operator()(Args&&... args) & {
return f(ref<F&>{f}, std::forward<Args>(args)...);
}
template <class... Args>
constexpr decltype(auto) operator()(Args&&... args) && {
return std::move(f)(ref<F&&>{std::move(f)}, std::forward<Args>(args)...);
}
};
constexpr auto fix = [](auto f) { return fix_t<decltype(f)>{f}; };
int main() {
auto once = fix([](auto f, int i) {
if (i <= 0)
return 0;
return 1 + f(i - 1);
});
auto const twice = fix([](auto f, int i) {
if (i <= 0)
return 0;
return 2 + f(i - 1);
});
auto thrice = fix([](auto f, int i) {
if (i <= 0)
return 0;
return 3 + f(i - 1);
});
return once(1) +
twice(2) +
std::move(thrice)(3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment