C++ Logo


Advanced search

[std-proposals] find_integral_constant

From: Sébastien Bini <sebastien.bini_at_[hidden]>
Date: Fri, 23 Sep 2022 19:29:40 +0200

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::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.

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.

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.

Received on 2022-09-23 17:29:52