递归可变参数模板无法推导出参数
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);
}
我有一个递归函数模板,其中类型 '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);
}