On Sat, Sep 24, 2022 at 4:05 AM Barry Revzin <barry.revzin@gmail.com> wrote:

On Fri, Sep 23, 2022 at 12:29 PM Sébastien Bini via Std-Proposals <std-proposals@lists.isocpp.org> 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

Damn, I hadn't seen that one. At least I am not the only one that needs it and came up with a similar API.

The range is just for convenience, just an upper bound is indeed sufficient. To be honest I never used it with a non-zero range start. But as it performs a binary search behind the scene, and as such needs a range, I figured it cost nothing to expose the range in the public API as well.

I don't know if I am thrilled by the return type though. What happens if the runtime index is outside the range? If this aims to be standardized then the API needs to be failure-tolerant.

Regards,
Sébastien Bini