Dig*_*Eye 10 c++ templates variadic-templates c++11
以下代码来自用户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;
}
Run Code Online (Sandbox Code Playgroud)
我对以上第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:这种技术可以归类为模板元编程吗?
Sam*_*hik 16
让我们来看看这里发生了什么:
template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> { };
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
Run Code Online (Sandbox Code Playgroud)
第一个是通用模板,第二个是在第一个模板参数为0时应用的特化.
现在,拿一张纸和一支铅笔,写下如何
gens<3>
Run Code Online (Sandbox Code Playgroud)
由上面的模板定义.如果您的答案是:
struct gens<3> : public gens<2, 2>
Run Code Online (Sandbox Code Playgroud)
那你是对的.这是第一个模板在N"3" 时展开的方式,并且...S是空的.gens<N - 1, N - 1, S...>因此,成为gens<2, 2>.
现在,让我们继续,看看如何gens<2, 2>定义:
struct gens<2, 2> : public gens<1, 1, 2>
Run Code Online (Sandbox Code Playgroud)
这里,在模板扩展中,N是2,并且...S是"2".现在,让我们进行下一步,看看如何gens<1, 1, 2>定义:
struct gens<1, 1, 2> : public gens<0, 0, 1, 2>
Run Code Online (Sandbox Code Playgroud)
好的,现在如何gens<0, 0, 1, 2>定义?它现在可以通过专业化来定义:
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
Run Code Online (Sandbox Code Playgroud)
那么,struct gens<0, 0, 1, 2>这里会发生什么?那么,在专业化中,"S ......"变成"0,1,2",所以这就变成了:
struct gens<0, 0, 1, 2> {
typedef seq<0, 1, 2> type;
}
Run Code Online (Sandbox Code Playgroud)
现在,请记住,所有这些都是公开继承的,"大象风格",所以:
gens<3>::type
Run Code Online (Sandbox Code Playgroud)
最终成为一个typedef声明
struct seq<0, 1, 2>
Run Code Online (Sandbox Code Playgroud)
使用另一个模板,使用以下代码将元组转换为参数包:
double delayed_dispatch()
{
return callFunc(typename gens<sizeof...(Args)>::type()); // Item #1
}
Run Code Online (Sandbox Code Playgroud)
...Args是元组参数.所以,如果元组中有三个元素,sizeof(...Args)则为3,正如我上面所解释的,gens<sizeof...(Args)>::type()变为gens<3>::type(),又名seq<0, 1, 2>().
那么,现在:
template<int ...S>
double callFunc(seq<S...>)
{
return func(std::get<S>(params) ...);
}
Run Code Online (Sandbox Code Playgroud)
该S...部分变为"0,1,2",所以
std::get<S>(params)...
Run Code Online (Sandbox Code Playgroud)
成为扩展为的参数包:
std::get<0>(params), std::get<1>(params), std::get<2>(params),
Run Code Online (Sandbox Code Playgroud)
这就是元组成为参数包的方式.