[英]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::tuple
和std::array
都需要有關元素數量的編譯時信息。 std::list
或std::vector
只能提供有關元素計數的運行時信息。
您的args_as_tuple
函數必須是一個模板,以預期的參數數量作為模板參數( args_as_tuple<4>(args_as_list)
)。
盡管必須將參數數量作為模板參數看似很苛刻,但是在您的示例中,這非常明顯-函數參數(提供給std::apply
函數)的數量也必須在編譯時知道。
對於更通用的代碼,您可以使用: function-traits或此答案中的代碼。
或使用乞討中的std::array
而不是std::list
(很多通用模板代碼,但編譯時檢查不錯)
std::tuple
或std::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.