On 3/10/2015 4:31 PM, Louis Dionne wrote:
Zach Laine <whatwasthataddress <at> gmail.com> writes:
On Sun, Mar 8, 2015 at 2:56 PM, Eric Niebler <eniebler <at> boost.org> wrote:
[...]
As for lazy branches, that can also be handled simply by let/defer:
// Test that the unselected branch does not get evaluated: template<typename T> using test_lazy_if_ = let<lazy::if_<std::is_void<T>, T, defer<std::pair, T> > >; static_assert(std::is_same<test_lazy_if_≤void>, void>::value, "");
And don't forget this part! :)
Oops, I forgot. Ok, so lazy branches in Hana work as follows. First, you use the `eval_if` function, which takes a condition and two branches in the form of lambdas. But that's not all; the lambdas must accept a parameter (usually called _), which can be used to defer the compile-time evaluation of expressions as required. An example:
template <typename N> auto fact(N n) { return hana::eval_if(n == hana::int_<0>, [](auto _) { return hana::int_<1>; }, [=](auto _) { return n * fact(_(n) - hana::int_<1>); } ); }
What happens here is that `eval_if` will pass an identity function to the selected branch. Hence, `_(x)` is always the same as `x`, but the compiler can't tell until the lambda has been called! Hence, the compiler has to wait before it instantiates the body of the lambda and no infinite recursion happens.
The identity function hack is a little unfortunate, but I understand the need for it. What if the two branches return different types? It seems like it /should/ work when passed a runtime int like 11, as well as when passed a compile-time integral constant wrapper like std::integral_constant<int,11>. Is that how it works? That would be nifty. For reference, with Meta: template<typename N> struct fact : let<lazy::if_c<(N::value > 0), lazy::multiplies<N, defer<fact, dec<N>>>, meta::size_t<1>>> {}; Obviously only a compile-time computation. <snip>
Also, there are several caveats. First, because we're using lambdas, it means that the function's result can't be used in a constant expression.
:-(
The second caveat is that compilers currently have several bugs regarding deeply nested lambdas with captures.
Meh. Bugs can be fixed.
Finally, it means that conditionals can't be written directly inside unevaluated contexts.
:-( <snip> Using lambdas for lazy conditionals brings limitations and pitfalls. Would you consider adding a pure type-level alternative for people doing straight metaprogramming? -- Eric Niebler Boost.org http://www.boost.org