我正在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 发生?