簡體   English   中英

非遞歸訪問自定義變體 - 如何優雅地返回值?

[英]Non-recursively visit a custom variant - how to elegantly return a value?

我正在為個人項目和學習體驗編寫std::variant的准系統版本。 我想要實現的訪問策略是if...else if鏈,而不是函數指針的constexpr表。 原因是后者對於編譯器來說是出了名的難以優化,並且很容易產生一個基准測試,其中std::visitif...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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM