元组到参数包 [英] Tuple to parameter pack
问题描述
以下来自用户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 togens<3>::type()
, but that doesn't seem to match neithertemplate<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { };
nortemplate<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屋!