递归可变参数模板无法推导出参数

recursive variadic template can't deduce argument

我有一个递归函数模板,其中类型 'T' 在内部使用,但可变参数模板参数仅用于生成递归模板。

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){})?

你 运行 遇到的问题是 qi<>(int )qi(int ) 不是同一个调用 - 前者仍然是一个模板,所以你试图写的重载你的基本情况实际上不是。自最初显而易见的解决方案以来,情况实际上更糟:

template <>
int qi(int ) { ... }

since 将不起作用,因为这不是您的 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...> 完成类似的事情(因为您 可以 部分特化 class 模板) .

如果您不想return任何事情,您可以转发给这样的帮助者:

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)...
    };
}

根据您的实际需要 return,这可能仍然可行,也可能不可行。

首先,声明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 困住了,没有明显的方法可以 'peel off' 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);
}