[英]Non-recursively visit a custom variant - how to elegantly return a value?
我正在為個人項目和學習體驗編寫std::variant
的准系統版本。 我想要實現的訪問策略是if...else if
鏈,而不是函數指針的constexpr
表。 原因是后者對於編譯器來說是出了名的難以優化,並且很容易產生一個基准測試,其中std::visit
被if...else if
鏈擊敗。
我正在嘗試使用fold 表達式來實現它,但是當找到正確的訪問者時,我找不到返回值的方法。 這是我到目前為止:
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 發生的訪問者的結果?
您需要選擇一個不會丟棄該值的運算符。
template <typename T>
struct result { // aka std::optional
std::aligned_storage_t<T> store;
bool has_value;
result() : has_value(false) {}
result(T t) : new(store) T(std::move(t)), has_value(true) {}
const result & operator| (const result & other) const { return has_value ? *this : other; }
T get() { return std::move(*reinterpret_cast<T *>(store)); }
};
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)...);
using result_t = result<std::common_type_t<std::invoke_result_t<matcher, Ts>...>>;
return [&]<std::size_t... Is>(std::index_sequence<Is...>)
{
return ([&]() -> result_t
{
if (_discriminator == Is)
{
// How to return from here?
return matcher(*reinterpret_cast<Ts *>(&_buffer));
}
return result_t{};
}() | ...);
}
(std::make_index_sequence_for<Ts...>{}).get();
}
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.