C++ Logo

std-proposals

Advanced search

Re: [std-proposals] find_integral_constant

From: Barry Revzin <barry.revzin_at_[hidden]>
Date: Fri, 23 Sep 2022 21:05:34 -0500
On Fri, Sep 23, 2022 at 12:29 PM S├ębastien Bini via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Hello,
>
> When dealing with variants and tuples, I often find myself in need to
> retrieve a variant element or a tuple element from a runtime index.
>
> For instance, consider variant serialisation. To serialize, you first
> write the index, then serialize the contained data. Problems come with
> deserialization: you first read the index and then... you realize that with
> the existing APIs, you cannot rebuild the variant element from the index we
> just read.
>
> So I managed to write the following function:
>
> // Func must have the following member function:
> // template <auto N>
> // void operator()(std::integral_constant<decltype(N), N>);
> template <auto From, auto To, class Int, class Func>
> void find_integral_constant(Int at, Func&& func);
>

> In my implementation, it performs a binary search to retrieve the integral
> constant that matches the given run-time index `at`, within the supplied
> range. If the index is not found (because out-of-bounds) then the functor
> is not called.
> It could also return a boolean that indicates if the supplied index is in
> the template range (true) or not (false). However I find it unnecessary as
> users can already get that information by checking whether the functor has
> been called, should they be interested in knowing that.
>
> Back to our deserialization problem, it is easily solved:
> std::find_integral_constant<0,
> std::variant_size_v<Variant>>(deserialized_index, [&](auto ID)
> { deserialize(variant_.template emplace<ID()>(), stream); });
>

> I believe such an API is missing in the STL. Also, having it standardized
> could allow for more optimization. We could use a jump table to the right
> integral_constant (like a compiler-generated switch with a case for each
> integral constant) rather than doing a binary search.
>

This is mp_with_index in Boost.Mp11 (
https://www.boost.org/doc/libs/master/libs/mp11/doc/html/mp11.html#mp_with_indexni_f).
It doesn't take a range [From, To) but rather just a single number that is
the upper bound [0, N), which is sufficient.

Peter's implementation has lots of manually written switch statements, so
it's quite efficient.

Barry


>
> The only drawback I see is that users will be tempted to use it in places
> where they shouldn't:
>
> for (std::size_t i = 0, e = std::tuple_size_v<Tpl>; i != e; ++i)
> {
> std::find_integral_constant<0, std::tuple_size_v<Tpl>>(i, [&](auto ID)
> { /* do something with the variant */;});
> }
>
> FWIW the reason why I named it find_integral_constant, is because it
> better emphasizes that a search (non-free operation) is performed.
> Hopefully it will deter some users from misusing it.
>
> Note:
> The template parameters could reworked to be more consistent:
> template <class Int, Int From, Int To, class Func>
> void find_integral_constant(Int at, Func&& func);
>
> But that adds an additional template parameter to specify by the caller.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2022-09-24 02:05:48