我愿意做一些简单的事情:
template <typename I, typename... In>
void bar() {
// Use I here
bar<In...>(); // Enable recursion
}
但是,这会导致“对重载函数的模糊调用”。 令我好奇的是,波纹管代码有效:
template <typename T = void>
void foo() { }
template <int T, int... Tn>
void foo() {
foo<Tn...>();
}
为什么? 以下也有效:
void foobar() {}
template <typename I, typename... In>
void foobar(I i, In... in) {
foobar(in...);
}
那么,最简单的方法是实现递归,假设这个函数签名没有使用任何支持 - 列表技术:
template <typename I, typename... In>
void bar();
答案 0 :(得分:3)
你可以用foo()
求解的方式解决:当Tn...
列表为空时,调用foo<>()
,因此{strong}类型的foo()
版本模板参数(但带有默认值)被调用(编译器匹配foo<>()
与foo<void>()
)。
对于bar()
,您可以切换整数和类型。
您可以添加接收带有默认值
的非类型模板参数的终端版本template <int = 0>
void bar()
{ }
因此,当您使用空bar()
类型列表调用In...
时,编译器会将bar<>()
与bar<0>()
匹配。
---编辑---
OP问
如果
foo<>()
与foo<void>()
匹配,为什么bar<>()
与bar<void>()
(template <typename Dummy = void>
而不是template <int = 0>)
匹配?换句话说,为什么它必须是template <int = 0>
(int
类型)吗?
首先,为什么foo()
有效?
因为有foo()
可变参数模板函数接收一个或多个整数,并且foo()
模板接收单一类型(默认)。
因此,当您调用foo<>
时,它与整数可变参数版本不匹配(因为至少需要一个整数)并匹配类型版本(激活void
默认类型)。 / p>
第二:为什么bar()
无法添加接收单一(和默认)类型的版本?
因为你有一个可变参数模板函数,它接收一种或多种类型
template <typename I, typename... In>
void bar ()
{ bar<In...>(); }
所以如果你添加一个版本接收一种类型(默认)
template <typename = void>
void bar ()
{ }
编译器遇到麻烦:当你使用最后一个类型调用bar()
时会选择哪个版本?
我的意思是:您调用bar<int, long>()
并且只调用可变参数版本。
但可变版本调用bar<long>()
。
现在的问题是bar()
的两个版本(可变参数和单一类型)都匹配。
所以编译器会给你一个错误。
诀窍是使用单个默认模板参数创建bar()
版本,该参数可以匹配空列表调用(foo<>()
),但不会与类型可变参数版本冲突。
可能的解决方案是int
,但您可以选择其他类型(char
,long
,unsigned long long
和其他类型),甚至可以选择基于模板的版本-template默认参数。
我的意思是......而不是
template <int = 0>
void bar ()
{ }
你可以使用
template <template <typename...> class = std::vector>
void bar()
{ }
这不是一个建议:我认为int = 0
更容易编写和理解。只是为了展示另一种可能的方式。
重点是添加一个接收单个默认值但不是类型名称的模板。