Date: Fri, 23 Sep 2022 14:00:38 -0400
On Fri, Sep 23, 2022 at 1:29 PM Sébastien Bini via Std-Proposals <
std-proposals_at_[hidden]> wrote:
>
> 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.
>
This sounds like you're trying to reinvent/expose something that
`std::variant` already needs internally. For example, `variant`'s
destructor needs to "destroy the active alternative," and std::visit needs
to "visit the active alternative," and so on, where "the active
alternative" is a dynamic run-time value (v.index()). You basically just
want a way to "construct the active alternative," where "the active
alternative" is a dynamic run-time value supplied by the caller.
In my from-scratch repo (circa 2017), I called this operation
`recursive_union::visit(N, lambda)`, where `recursive_union` is simply a
`variant` that doesn't store the active index. (So, `std::variant` is a
class with two data members: a `recursive_union u` and a `size_t index`.)
https://github.com/Quuxplusone/from-scratch/blob/master/include/scratch/bits/variant/recursive-union.h#L44
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); });
>
This could be spelled more ergonomically as:
variant_.dynamic_emplace(deserialized_index, [](auto *p) {
std::construct_at(p); deserialize(*p, stream);
});
where you just pass in the index you want to activate, and then the variant
calls your visitor with an appropriate `T*` pointer for you to construct
into.
In other words:
std::variant<int, std::string> v;
v.emplace<1>("hello"); // legal in C++17, but requires a
compile-time-constant template argument 1
v.dynamic_emplace(1, [](auto *p) {
if constexpr (std::same_as<decltype(p), std::string*>) {
std::construct_at(p, "hello");
}
}); // silly, but legal, in C++Fantasy; permits a run-time-computed
function argument 1
Your utility to turn a runtime value into a compile-time integral_constant
is certainly more general, but also vastly more expensive (one line of code
could blow up into 256 or 65536 instantiations of that generic lambda's
operator() template!) and I don't immediately see any really killer app for
it. If you need this *only* for `variant`, then it seems like the
generality isn't needed.
my $.02,
Arthur
std-proposals_at_[hidden]> wrote:
>
> 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.
>
This sounds like you're trying to reinvent/expose something that
`std::variant` already needs internally. For example, `variant`'s
destructor needs to "destroy the active alternative," and std::visit needs
to "visit the active alternative," and so on, where "the active
alternative" is a dynamic run-time value (v.index()). You basically just
want a way to "construct the active alternative," where "the active
alternative" is a dynamic run-time value supplied by the caller.
In my from-scratch repo (circa 2017), I called this operation
`recursive_union::visit(N, lambda)`, where `recursive_union` is simply a
`variant` that doesn't store the active index. (So, `std::variant` is a
class with two data members: a `recursive_union u` and a `size_t index`.)
https://github.com/Quuxplusone/from-scratch/blob/master/include/scratch/bits/variant/recursive-union.h#L44
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); });
>
This could be spelled more ergonomically as:
variant_.dynamic_emplace(deserialized_index, [](auto *p) {
std::construct_at(p); deserialize(*p, stream);
});
where you just pass in the index you want to activate, and then the variant
calls your visitor with an appropriate `T*` pointer for you to construct
into.
In other words:
std::variant<int, std::string> v;
v.emplace<1>("hello"); // legal in C++17, but requires a
compile-time-constant template argument 1
v.dynamic_emplace(1, [](auto *p) {
if constexpr (std::same_as<decltype(p), std::string*>) {
std::construct_at(p, "hello");
}
}); // silly, but legal, in C++Fantasy; permits a run-time-computed
function argument 1
Your utility to turn a runtime value into a compile-time integral_constant
is certainly more general, but also vastly more expensive (one line of code
could blow up into 256 or 65536 instantiations of that generic lambda's
operator() template!) and I don't immediately see any really killer app for
it. If you need this *only* for `variant`, then it seems like the
generality isn't needed.
my $.02,
Arthur
Received on 2022-09-23 18:00:51