【发布时间】:2020-03-04 10:37:18
【问题描述】:
我正在为个人项目和学习体验编写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 发生?
【问题讨论】:
-
我想你想要this approach。
标签: c++ templates variant c++20 fold-expression