我试图使用可变参数模板编写我的第一个程序。具体包装延迟函数调用的参数。我最初假设调用如下所示的函数指针不起作用:
template<typename... params>
void TypeX<params...>::delayed_call()
{
auto xs = get_saved_args(); // returns tuple
(*func)(xs...);
}
环顾四周后,我找到了这个答案C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args?
用户Kerrek SB的回答非常有效,并且看起来比其他选择更好。不幸的是,我只是部分了解它。这是他的回答:
// implementation details, users never invoke these directly
namespace detail
{
template <typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl
{
static void call(F f, Tuple && t)
{
call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));
}
};
template <typename F, typename Tuple, int Total, int... N>
struct call_impl<F, Tuple, true, Total, N...>
{
static void call(F f, Tuple && t)
{
f(std::get<N>(std::forward<Tuple>(t))...);
}
};
}
// user invokes this
template <typename F, typename Tuple>
void call(F f, Tuple && t)
{
typedef typename std::decay<Tuple>::type ttype;
detail::call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
}
我知道这是一个递归解决方案,一旦达到部分专用版本就会终止。我无法理解流程,f(std::get<N>(std::forward<Tuple>(t))...);
到底是如何变成一个解压缩的调用。理想情况下,我希望从用户可调用函数调用中看到流的详细描述。
答案 0 :(得分:1)
盯着这一段时间后,我终于找到了合乎逻辑的东西。这是我对这个解包实现的理解。为了清楚起见,我在代码中添加了注释。
template <typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl
{
static void call(F f, Tuple && t)
{
call_impl<F,
Tuple,
Total == 1 + sizeof...(N),
Total,
// This is the tricky part: Initial N... is empty, so
// sizeof...(N) is going to be 0, which is fed to next
// call_impl. On subsequent invokation of "call" N will
// contain a single entry - '0'. All subsequent invokations
// will keep adding numbers to N until
// Total == 1 + sizeof...(N)
// evaluates to true. At that point template
// specialization below gets invoked and completes the
// recursive chain.
N...,
sizeof...(N)>::call(f, std::forward<Tuple>(t));
}
};
template <typename F, typename Tuple, int Total, int... N>
struct call_impl<F, Tuple, true, Total, N...>
{
static void call(F f, Tuple && t)
{
// This is the last call in the recusrive chain, so int... N is
// actually a tuple of numbers (unless the function being invoked takes
// no arguments)
// Ellipsis(...) causes the line below to be expanded to however many
// numbers the int... N contains:
// f(std::get<0>(std::forward<Tuple>(t)),
// std::get<1>(std::forward<Tuple>(t)),
// std::get<2>(std::forward<Tuple>(t))
// ...
// );
f(std::get<N>(std::forward<Tuple>(t))...);
}
};
// user invokes this
template <typename F, typename Tuple>
void call(F f, Tuple && t)
{
// Strip all qualifiers from Tuple: constness, volatility, reference
// and return the typedef of underfyling Tuple type
typedef typename std::decay<Tuple>::type ttype;
// ttype should now be a plain tuple type, so tuple_size will return its
// size
// IMPORTANT: The int... N is not given below, which drives the recursive
// compilation
call_impl<F,
Tuple,
0 == std::tuple_size<ttype>::value, // for no argument functions this is
// always true, which doesn't trigger recursive call_impl, but
// immediately drops to partially specialized call_impl, which
// invokes the given function.
std::tuple_size<ttype>::value
/*int... N would go here, but nothing is supplied */
>::call(f, std::forward<Tuple>(t));
}