[英]Tuple to parameter pack
以下代碼來自用戶Faheem Mitha,基於用戶Johannes Schaub - litb在此SO中的答案。 這段代碼完美地完成了我所尋求的,即將tuple
轉換為參數包,但我不太了解這段代碼,因此我想我會創建一個新的討論,可能有助於像我這樣的模板元編程新手。 所以,請原諒重復的帖子。
現在轉到代碼
#include <tuple>
#include <iostream>
using std::cout;
using std::endl;
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { };
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
double foo(int x, float y, double z)
{
return x + y + z;
}
template <typename ...Args>
struct save_it_for_later
{
std::tuple<Args...> params;
double(*func)(Args...);
double delayed_dispatch()
{
return callFunc(typename gens<sizeof...(Args)>::type()); // Item #1
}
template<int ...S>
double callFunc(seq<S...>)
{
return func(std::get<S>(params) ...);
}
};
int main(void)
{
std::tuple<int, float, double> t = std::make_tuple(1, (float)1.2, 5);
save_it_for_later<int, float, double> saved = { t, foo };
cout << saved.delayed_dispatch() << endl;
return 0;
}
我對以上第1項完全感到困惑:
typename
在該行上的用途是什么? gens<sizeof...(Args)>::type()
將擴展為gens<3>::type()
,但這似乎不匹配template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { };
也不是template<int ...S> struct gens<0, S...>
。 我顯然忽略了這一點,如果有人能解釋這里發生的事情,我會很高興。 我確實理解callFunc
在這個形式的callFunc(seq<0,1,2>)
被調用,並且這個方法的return語句本身擴展為return func(std::get<0>(params), std::get<1>(params), std::get<2>(params)
這就是使這個方案有效的原因,但我無法研究如何生成這個seq<0,1,2>
類型。
注意:使用std::index_sequence_for
不是一個選項,我的編譯器不支持C ++ 14功能。
PS:這種技術可以歸類為模板元編程嗎?
讓我們來看看這里發生了什么:
template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { };
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
第一個是通用模板,第二個是在第一個模板參數為0時應用的特化。
現在,拿一張紙和一支鉛筆,寫下如何
gens<3>
由上面的模板定義。 如果您的答案是:
struct gens<3> : public gens<2, 2>
那你是對的。 這是當N
為“3”時第一個模板擴展的方式,並且...S
為空。 gens<N - 1, N - 1, S...>
成為gens<2, 2>
。
現在,讓我們繼續,看看如何定義gens<2, 2>
:
struct gens<2, 2> : public gens<1, 1, 2>
這里,在模板擴展中, N
是2,並且...S
是“2”。 現在,讓我們進行下一步,看看如何定義gens<1, 1, 2>
:
struct gens<1, 1, 2> : public gens<0, 0, 1, 2>
好的,現在如何定義gens<0, 0, 1, 2>
? 它現在可以通過專業化來定義:
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
那么, struct gens<0, 0, 1, 2>
在這里會發生什么? 那么,在專業化中,“S ......”變成“0,1,2”,所以這就變成了:
struct gens<0, 0, 1, 2> {
typedef seq<0, 1, 2> type;
}
現在,請記住,所有這些都是公開繼承的,“大象風格”,所以:
gens<3>::type
最終成為一個typedef聲明
struct seq<0, 1, 2>
使用另一個模板,使用以下代碼將元組轉換為參數包:
double delayed_dispatch()
{
return callFunc(typename gens<sizeof...(Args)>::type()); // Item #1
}
...Args
是元組參數。 因此,如果元組中有三個元素,則sizeof(...Args)
為3,正如我上面所解釋的, gens<sizeof...(Args)>::type()
變為gens<3>::type()
,aka seq<0, 1, 2>()
。
那么,現在:
template<int ...S>
double callFunc(seq<S...>)
{
return func(std::get<S>(params) ...);
}
S...
部分變為“0,1,2”,所以
std::get<S>(params)...
成為擴展為的參數包:
std::get<0>(params), std::get<1>(params), std::get<2>(params),
這就是元組成為參數包的方式。
使用C ++ 17,您可以使用“if constexpr”來創建序列包裝器:
template <int indxMax, template <int... > class spack, int ... seq>
constexpr auto get_seq17()
{
static_assert(indxMax >= 0, "Sequence size must be equal to or greater than 0!");
if constexpr (indxMax > 0)
{
typedef decltype(spack<indxMax, seq...>{}) frst;
constexpr int next = indxMax - 1;
return get_seq17<next, spack, indxMax, seq...>();
}
else
{
return spack<indxMax, seq...>{};
}
}
template <int indxMax, template <int...> class pack>
struct seq_pack
{
typedef decltype(get_seq17<indxMax, pack>()) seq;
};
//creating a sequence wrapper
template <int ... seq>
struct seqpack {};
//usage
seq_pack<4, seqpack>::seq; //seqpack<0, 1, 2, 3, 4>
雖然這個實現更容易理解,但最好使用std::make_index_sequence<Size>
正如Julius在下面的評論中提到的那樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.