Я пишу базовую версию std::variant
для личного проекта и опыта обучения. Стратегия посещения, которую я хочу реализовать, представляет собой цепочку if...else if
, а не таблицу указателей функций constexpr
. Причина в том, что последний, как известно, трудно компилятору оптимизировать, и легко создать эталон, где std::visit
побежден цепочкой if...else if
.
Я пытаюсь реализовать это с помощью сложить выражения , но я не смог найти способ вернуть значение, когда найден правильный посетитель. Вот что у меня есть:
template <typename... Ts>
struct my_variant
{
std::byte _buffer[std::max({sizeof(Ts)...})];
std::size_t _discriminator;
// ...
auto match(auto&&... fs)
{
overload_set matcher(std::forward<Fs>(fs)...);
[&]<std::size_t... Is>(std::index_sequence<Is...>)
{
([&]
{
if (_discriminator == Is)
{
// How to return from here?
matcher(*reinterpret_cast<Ts *>(&_buffer));
}
}(), ...);
}
(std::make_index_sequence_for<Ts...>{});
}
};
Моя текущая стратегия - создать std::index_sequence
для всех типов в варианте, затем сложить оператор запятой, чтобы компилятор генерировал кучу if
заявления. Поскольку if
не является выражением, мне пришлось заключить его в лямбда-выражение , чтобы можно было его сложить. Если я попытаюсь вернуться, я вернусь из самой лямбды, и это не распространяется на верхние уровни.
Я мог бы использовать буфер для хранения результата, а затем вернуть его, но это противоречит цели как это предотвратит RVO.
Есть ли способ, которым я могу писать match
не рекурсивно и по-прежнему возвращать результат посетителя, позволяющий RVO иметь место?