簡體   English   中英

從標准容器生成std :: tuple

[英]Generate a std::tuple from standard container

有沒有一種可移植的方式從容器的內容生成std::tuple (實際上是std::array )? 這樣的元組將允許std::apply從容器中提取函數參數。

我的首次嘗試使用尾遞歸失敗,並出現編譯器錯誤:“遞歸模板實例化超過了最大值...”。

我無法完全嘗試第二次嘗試( std::for_each帶有一個持有元組的可變lambda)來編譯所需的結果。

我認為可以使boost::mpl處理可變元函數(例如,使用boost::preprocessor魔術)可以正常工作-但這就是c ++ 03。 我希望有更好的解決方案。

函數簽名看起來像:

std::list<int> args_as_list = {1, 2, 3, 4};
auto tpl = args_as_tuple(args_as_list);

其中tpl類型為std::array<int const, 4>

簡短的回答: ,這是不可能的。

說明: std::tuplestd::array都需要有關元素數量的編譯時信息。 std::liststd::vector只能提供有關元素計數的運行時信息。

您的args_as_tuple函數必須是一個模板,以預期的參數數量作為模板參數( args_as_tuple<4>(args_as_list) )。

盡管必須將參數數量作為模板參數看似很苛刻,但是在您的示例中,這非常明顯-函數參數(提供給std::apply函數)的數量也必須在編譯時知道。
對於更通用的代碼,您可以使用: function-traits此答案中的代碼。
或使用乞討中的std::array而不是std::list (很多通用模板代碼,但編譯時檢查不錯)

std::tuplestd::array的元素數量是其類型信息的一部分。 因此,您args_as_tuple建議的函數args_as_tuple某種程度上必須是模板,結果的每個不同可能大小都需要該模板的不同實例化。 因此,除非該程序的代碼是無限的(不可能),否則您不能制作一個可以支持任意大小的元組的程序。

例如,如果只關心int的值范圍,則可以實例化模板40億次,但是可執行文件的大小至少為4 GB。

如果您真的只關心實際程序中向量的幾種不同大小,則可以僅實例化那些模板並編寫轉換代碼, 區分std::list::size()並調用適當的函數(乏味)。

但是您的確切代碼段

std::list<int> args_as_list = {1, 2, 3, 4};
auto tpl = args_as_tuple(args_as_list);

永遠無法在C ++中工作 因為在C ++中,所有變量都必須具有在編譯時確定的已知類型。 即使您使用關鍵字auto ,該auto也必須在編譯時解析為固定類型,如果它是元組或數組,則意味着固定大小,而不管表達式args_as_tuple在做什么模板。

由於我的問題無法解決,因此我解決了一個略有不同的問題,這使我得以繼續。

我想出了一個解決方案,使我可以從容器中提取函子的參數。 我能夠用我要評估的函子實例化eval_container ,然后將容器傳遞給結果對象。

#include <utility>

template <int N>
using Int = std::integral_constant<int, N>;

template <typename T>
struct arity : arity<decltype(&T::operator())> {};

template <typename T, typename RT, typename...Args>
struct arity<RT(T::*)(Args...) const>
{
    // could enforce maximum number of arguments
    static constexpr int value = sizeof...(Args);
};

template <typename F, int N = arity<F>::value>
struct eval_container
{
    eval_container(F const& f) : f(f) {}
    eval_container(F&& f) : f(std::move(f)) {}

    template <typename Iter, typename I, typename...Args>
    auto operator()(Iter&& iter, I, Args&&...args) const
    {
        // assert(iter != end)
        auto&& arg = *iter++;
        return (*this)(std::forward<Iter>(iter)
                     , Int<I()-1>{}
                     , std::forward<Args>(args)...
                     , arg);
    }

    template <typename Iter, typename...Args>
    auto operator()(Iter&&, Int<0>, Args&&...args) const
    {
        // assert(iter == end)
        return f(std::forward<Args>(args)...);
    }

    template <typename C>
    auto operator()(C const& container) const
    {
        return (*this)(container.begin(), Int<N>{});
    }

    F f;
};

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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