Last active
June 11, 2020 13:16
-
-
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
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> | |
#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