元组到参数包 [英] Tuple to parameter pack

查看:60
本文介绍了元组到参数包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下来自用户Faheem Mitha的代码基于用户Johannes Schaub-在 SO 中,litb的回答。这段代码完全可以满足我的要求,即将 tuple 转换为参数包,但是我对此代码的理解不够充分,因此我想我将创建一个新的代码。可能有助于模板元编程新手的讨论。因此,请原谅重复的发布。

This below code from user Faheem Mitha, is based on user Johannes Schaub - litb's answer in this SO. This code perfectly does what I seek, which is conversion of a tuple into parameter pack, but I don't understand this code well enough and therefore I thought I will create a new discussion that might help template metaprogramming newbies like me. So, please pardon the duplicate posting.

现在移到代码上

#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项所迷惑:

I'm completely confounded by Item #1 above:


  • typename 在该行有什么作用?

  • 我知道 gens< sizeof ...(Args)> :: type()将扩展为 gens< 3> :: type() ,但这似乎与 template< int N,int ... S>都不匹配。结构gens:gens< N-1,N-1,S ...> {}; template< int ... S> struct gens< 0,S ...> 。我显然不明白要点,很高兴有人可以解释这里发生的事情。

  • What purpose does typename serve on that line?
  • I understand that gens<sizeof...(Args)>::type() will expand to gens<3>::type(), but that doesn't seem to match neither template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { }; nor template<int ...S> struct gens<0, S...>. I'm obviously missing the point and I'd be glad if someone can explain what is happening here.

我确实理解 callFunc 以这种形式被调用 callFunc(seq< 0,1,2>)以及此方法本身的return语句扩展为返回函数(std :: get< 0>(params),std :: get< 1>(params),std :: get< 2>(params)这就是使该方案起作用的原因,但我无法确定如何生成 seq< 0,1,2> 类型。

I do understand that callFunc gets invoked in this form callFunc(seq<0,1,2>) and the return statement of this method itself expands to return func(std::get<0>(params), std::get<1>(params), std::get<2>(params) and this is what makes this scheme work, but I cannot workout how this seq<0,1,2> type is generated.

注意:不能使用 std :: index_sequence_for ,我的编译器不支持C ++ 14功能。

Note: Using std::index_sequence_for is not an option, my compiler doesn't support C++14 features.

PS:可以将此技术归类为模板元编程吗?

PS: Can this technique be classified as template metaprogramming?

推荐答案

让我们看看这里发生了什么:

Let's look at what happens here:

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。

The first one is a generic template, the second one is a specialization that applies when the first template parameter is 0.

现在,拿一支纸和铅笔,写下如何做

Now, take a piece of paper and pencil, and write down how

 gens<3>

由上述模板定义。如果您的答案是:

gets defined by the above template. If your answer was:

 struct gens<3> : public gens<2, 2>

那么您是对的。这就是当 N 为 3且 ... S 为空时第一个模板的扩展方式。 gens< N-1,N-1,S ...> ,因此成为 gens< 2,2>

then you were right. That's how the first template gets expanded when N is "3", and ...S is empty. gens<N - 1, N - 1, S...>, therefore, becomes gens<2, 2>.

现在,让我们继续,看看 gens< 2,2> 是如何定义的:

Now, let's keep going, and see how gens<2, 2> gets defined:

 struct gens<2, 2> : public gens<1, 1, 2>

此处,在模板扩展中, N 是2,而 ... S 是 2。现在,让我们进行下一步,看看如何定义 gens< 1、1、2>

Here, in the template expansion, N is 2, and ...S is "2". Now, let's take the next step, and see how gens<1, 1, 2> is defined:

 struct gens<1, 1, 2> : public gens<0, 0, 1, 2>

好了,现在 gens <0,0,1,2> 被定义了吗?现在可以通过专业化来定义:

Ok, now how does gens<0, 0, 1, 2> gets defined? It can now be defined by the specialization:

 template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };

因此, struct gens< 0,0,1,2>会发生什么? ; 在这里?好吧,在专业化中, S ...变为 0,1,2,因此从某种意义上说变为:

So, what happens with struct gens<0, 0, 1, 2> here? Well, in the specialization, "S..." becomes "0, 1, 2", so this becomes, in a manner of speaking:

 struct gens<0, 0, 1, 2> {

   typedef seq<0, 1, 2> type;

 }

现在,请记住,所有这些都是从彼此大象式,因此:

Now, keep in mind that all of these publicly inherit from each other, "elephant-style", so:

 gens<3>::type

最终成为typedef声明,用于

ends up being a typedef declaration for

 struct seq<0, 1, 2>

以下代码将其用于将元组转换为参数包,并使用另一个模板:

And this is used, by the code that follows to convert the tuple into a parameter pack, using another template:

double delayed_dispatch()
{
    return callFunc(typename gens<sizeof...(Args)>::type()); // Item #1
}

... Args 是元组参数。因此,如果元组中包含三个元素,则 sizeof(... Args)为3,正如我上面已经解释的那样, gens< sizeof ...(Args)> :: type()变为 gens< 3> :: type(),也称为 seq< 0,1,2>()

...Args are the tuple parameters. So, if there are three elements in the tuple, sizeof(...Args) is 3, and as I've explained above, gens<sizeof...(Args)>::type() becomes gens<3>::type(), a.k.a. seq<0, 1, 2>().

所以,现在:

template<int ...S>
double callFunc(seq<S...>)
{
    return func(std::get<S>(params) ...);
}

S ... 部分变为 0、1、2,因此

The S... part becomes "0, 1, 2", so the

std::get<S>(params)...

成为参数包,并扩展为:

Becomes a parameter pack that gets expanded to:

std::get<0>(params), std::get<1>(params), std::get<2>(params),

这就是元组变成参数包的方式。

And that's how a tuple becomes a parameter pack.

这篇关于元组到参数包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆