使用C ++ 11中的模板参数的递归可变参数void函数

时间:2018-03-11 15:53:52

标签: c++ c++11 templates recursion variadic-templates

我愿意做一些简单的事情:

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();

1 个答案:

答案 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,但您可以选择其他类型(charlongunsigned long long和其他类型),甚至可以选择基于模板的版本-template默认参数。

我的意思是......而不是

template <int = 0>
void bar ()
 { }

你可以使用

template <template <typename...> class = std::vector>
void bar()
 { }

这不是一个建议:我认为int = 0更容易编写和理解。只是为了展示另一种可能的方式。

重点是添加一个接收单个默认值但不是类型名称的模板。