簡體   English   中英

元組到參數包

[英]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.

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