我正在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不是一个表达式,我不得不将它包装成一个lambda 表达式以便能够折叠它。如果我尝试返回,我将从 lambda 本身返回,并且不会传播到上层。
我可以使用缓冲区来存储结果,然后返回它,但这违背了目的,因为它会阻止 RVO。
有没有一种方法可以非递归地编写match并且仍然返回访问者的结果允许 RVO 发生?