[英]Tuple to parameter pack
This below code from user Faheem Mitha, is based on user Johannes Schaub - litb's answer in this SO . 以下代码来自用户Faheem Mitha,基于用户Johannes Schaub - litb在此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. 这段代码完美地完成了我所寻求的,即将
tuple
转换为参数包,但我不太了解这段代码,因此我想我会创建一个新的讨论,可能有助于像我这样的模板元编程新手。 So, please pardon the duplicate posting. 所以,请原谅重复的帖子。
Now moving onto the code 现在转到代码
#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;
}
I'm completely confounded by Item #1 above: 我对以上第1项完全感到困惑:
typename
serve on that line? typename
在该行上的用途是什么? 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...> { };
gens<sizeof...(Args)>::type()
将扩展为gens<3>::type()
,但这似乎不匹配template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { };
nor template<int ...S> struct gens<0, S...>
. 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. 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. 我确实理解
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>
类型。
Note: Using std::index_sequence_for
is not an option, my compiler doesn't support C++14 features. 注意:使用
std::index_sequence_for
不是一个选项,我的编译器不支持C ++ 14功能。
PS: Can this technique be classified as template metaprogramming? PS:这种技术可以归类为模板元编程吗?
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; };
The first one is a generic template, the second one is a specialization that applies when the first template parameter is 0. 第一个是通用模板,第二个是在第一个模板参数为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>
then you were right. 那你是对的。 That's how the first template gets expanded when
N
is "3", and ...S
is empty. 这是当
N
为“3”时第一个模板扩展的方式,并且...S
为空。 gens<N - 1, N - 1, S...>
, therefore, becomes gens<2, 2>
. gens<N - 1, N - 1, S...>
成为gens<2, 2>
。
Now, let's keep going, and see how gens<2, 2>
gets defined: 现在,让我们继续,看看如何定义
gens<2, 2>
:
struct gens<2, 2> : public gens<1, 1, 2>
Here, in the template expansion, N
is 2, and ...S
is "2". 这里,在模板扩展中,
N
是2,并且...S
是“2”。 Now, let's take the next step, and see how gens<1, 1, 2>
is defined: 现在,让我们进行下一步,看看如何定义
gens<1, 1, 2>
:
struct gens<1, 1, 2> : public gens<0, 0, 1, 2>
Ok, now how does gens<0, 0, 1, 2>
gets defined? 好的,现在如何定义
gens<0, 0, 1, 2>
? It can now be defined by the specialization: 它现在可以通过专业化来定义:
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
So, what happens with struct gens<0, 0, 1, 2>
here? 那么,
struct gens<0, 0, 1, 2>
在这里会发生什么? Well, in the specialization, "S..." becomes "0, 1, 2", so this becomes, in a manner of speaking: 那么,在专业化中,“S ......”变成“0,1,2”,所以这就变成了:
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
ends up being a typedef declaration for 最终成为一个typedef声明
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
are the tuple parameters. ...Args
是元组参数。 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()
, aka seq<0, 1, 2>()
. 因此,如果元组中有三个元素,则
sizeof(...Args)
为3,正如我上面所解释的, gens<sizeof...(Args)>::type()
变为gens<3>::type()
,aka seq<0, 1, 2>()
。
So, now: 那么,现在:
template<int ...S>
double callFunc(seq<S...>)
{
return func(std::get<S>(params) ...);
}
The S...
part becomes "0, 1, 2", so the S...
部分变为“0,1,2”,所以
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. 这就是元组成为参数包的方式。
With C++17 you can use "if constexpr" to create a sequence wrapper: 使用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>
Though this implementation is easier to understand, it is preferable to use std::make_index_sequence<Size>
as Julius has mentioned in the comments below. 虽然这个实现更容易理解,但最好使用
std::make_index_sequence<Size>
正如Julius在下面的评论中提到的那样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.