我有一个带有varargs template arguments的模板函数,像这样
template<typename Args...>
void ascendingPrint(Args... args) { /* ... */ }
我想写
template<typename Args...>
void descendingPrint(Args... args) {
/* implementation using ascendingPrint()? */
}
我如何在传递参数包之前颠倒参数包 的顺序args
,即使用伪代码:
template<typename Args...>
void descendingPrint(Args... args) {
ascendingPrint( reverse(args) );
}
这是专门的递归实现revert<>
:
// forward decl
template<class ...Tn>
struct revert;
// recursion anchor
template<>
struct revert<>
{
template<class ...Un>
static void apply(Un const&... un)
{
ascendingPrint(un...);
}
};
// recursion
template<class T, class ...Tn>
struct revert<T, Tn...>
{
template<class ...Un>
static void apply(T const& t, Tn const&... tn, Un const&... un)
{
// bubble 1st parameter backwards
revert<Tn...>::apply(tn..., t, un...);
}
};
// using recursive function
template<class A, class ...An>
void descendingPrint(A const& a, An const&... an)
{
revert<An...>::apply(an..., a);
}
它可以与gcc-4.6 / 7/8和clang一起使用,并且可能符合标准 -唯一困难的部分是的调用revert<Tn...>::apply(tn..., t, un...)
。
但是,它有缺点(就像递归一样),它会生成很多目标函数的模板实例(代码膨胀),并且没有使用完美的转发,这可能是个问题(但使用它可能会有所改进) 。
漂亮,看起来就像Haskell到TMP / smile /的字面翻译。看起来很简单。为什么说“适用于gcc 4.8”?你不认为它的标准吗?我不明白为什么不是。您是否担心多参数包的
apply
?据我所记得,函数模板 可以有多个参数包,只有类模板不能。留下apply(tn..., t, un...)
问题,编译器是否可以正确展开所有参数。“以身作则”(gcc)似乎应该,但是标准也这样说吗?@towi谢谢!我认为这是std C ++,但是gcc 4.8是我测试过的唯一编译器。这是一个稍作修改的版本。适用于gcc 4.6 / 7/8和clang,但不适用于Intel编译器。
我接受了您对非递归答案的支持,因为我自己喜欢递归,而这个版本对我来说是最容易理解的。但这是一个艰难的选择:我敦促读者也阅读其他的答案。AndyPowl和Xeo(也许还有评论)-他们可能会为您带来好处。和MM有一个点也一样,如果你并不需要一个通用的解决方案。
我认为在这里值得一提的是,我们总是在这种递归情况下强制进行内联,即使在进行灯光优化的情况下,也可以显着提高性能。