我有一个递归函数模板,其中类型'T'在内部使用,但variadic模板参数仅用于生成递归模板。
int qi(int t) {
return 0;
}
template <typename T, typename... U>
int qi(int t) {
//do stuff...
return qi<U...>(t); // <--- error here
}
如果我尝试编译它,我会收到错误could not deduce template argument for 'T'
。为什么不能将函数推导到qi(int qi(int t){}
)的非模板变体?
答案 0 :(得分:3)
您遇到的问题是qi<>(int )
和qi(int )
不是同一个调用 - 前者仍然是模板,因此您尝试写入的重载实际上是您的基本情况ISN&#39;吨。自从最初明显的解决方案以来,它实际上更糟糕了:
template <>
int qi(int ) { ... }
因为没有工作,因为这不是qi
的明确专业化(因为你的函数模板至少需要一种类型)。最简单的方法是实际使用参数重载:
template <typename...> struct sequence { };
template <typename... T>
int qi(int t) { return qi_helper(t, sequence<T...>{} ); }
使用:
template <typename T, typename... U>
int qi_helper(int t, sequence<T, U...> ) {
// do stuff
return qi_helper(t, sequence<U...>{});
}
int qi_helper(int t, sequence<> ) {
// base case
}
您可以使用专门针对这两种情况的结构QiHelper<T...>
来完成类似的事情(因为您可以部分地专门化类模板)。
如果您不想退货,可以转发给这样的帮手:
template <typename T> void qi_helper(int t) {
/* logic for single type */
}
template <typename... T>
void qi(int t) {
using swallow = int[];
(void)swallow{0,
(void(qi_helper<T>(t)), 0)...
};
}
取决于您实际想要返回的内容,可能会或可能不会。
答案 1 :(得分:3)
首先,声明qi
以任意数量的模板参数,包括零参数。
template <typename... TU>
extern
int qi(int t);
我们最终必须提供这方面的实施。但首先,我们可以提供任意数量的完全专业化(非部分专业化)模板。所以,我们实现了零参数:
template < >
int qi< >(int ) {
return 0;
}
这是一项专业化(因为<
之后有qi
)和完全专业化(因为< >
之后的template
为空。
我们现在想要实现非专业的qi
模板。我们不允许进行任何部分专业化,我们不希望完全专业化,因为这意味着必须实现您可能使用的每一组类型。这意味着我们必须使用此签名实现某些内容:template <typename... TU> int qi(int t) ...
我们坚持使用TU
,没有明显的方法可以“剥离”T
以保留包U...
。最简单的方法是将实现传递给辅助函数:
template<typename T, typename... U>
int qi_helper(int t) {
// do any other interesting stuff
return qi<U...>(t);
}
template <typename... TU>
int qi(int t) {
// just pass on the call to qi_helper
return qi_helper<TU...>(t);
}