Boost logo

Boost :

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

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk