$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [mpl] multiset
From: Eric Niebler (eniebler_at_[hidden])
Date: 2015-03-11 02:42:29
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