递归可变参数模板不能推导出参数

时间:2015-07-09 19:21:41

标签: c++ templates recursion variadic-templates

我有一个递归函数模板,其中类型'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){})的非模​​板变体?

2 个答案:

答案 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);
}