C ++多个可变参数模板未绑定到函数参数

时间:2015-12-29 02:04:14

标签: c++ templates c++14 variadic

我试图使用一些可变参数模板参数,但我很快被一个我无法理解的错误所阻止。

#include <tuple>

template <typename T>
struct Foo
{
  typedef T type;
};

// return a tuple of pair of args and Foo templated on Types
template <typename Head, typename ...Args, typename Type, typename ...Types>
auto func(Head arg, Args... args)
{
  return std::tuple_cat(std::make_tuple(std::make_pair(arg, Foo<Type>())),
                       func<Args..., Types...>(args...));
}

template <typename Head, typename Type>
auto func(Head arg)
{
  return std::make_tuple(std::make_pair(arg, Foo<Type>()));
}

int main()
{
  func<int, bool, char>(1, 2, 3);
}

这里func尝试解压缩模板参数,并在第二个可变参数模板上创建一对func参数和Foo结构的元组,但我有:

test.cc:25:3: error: no matching function for call to 'func'
 func<int, bool, char>(1, 2, 3);
 ^~~~~~~~~~~~~~~~~~~~~
test.cc:11:6: note: candidate template ignored: couldn't infer template argument 'Type'
 auto func(Head arg, Args... args)
 ^
test.cc:18:6: note: candidate function template not viable: requires single argument 'arg', but 3
  arguments were provided
 auto func(Head arg)
 ^
 1 error generated.

为什么无法推断出类型? (gcc告诉我同样的事情)

我确信在查看std :: tuple_cat实现(https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a01066_source.html)之后可以使用多个可变参数模板,我认为这是一个简单的示例,如果有解决方案或标准,有人应该更清楚我不接受这个。

感谢您的帮助,

2 个答案:

答案 0 :(得分:2)

将推断出的论点放在最后。

...模板参数是贪婪的 - 它们将使用参数传递,并且不会“保存”任何以后的模板参数。

完成后,从非模板函数参数中进行推导。

像这样交换:

template <typename Type, typename ...Types, typename Head, typename ...Args>
auto func(Head arg, Args... args)

另外,摆脱其他重载,因此func<int,int>(3)不明确。

这会使递归中断,但这很容易修复:

template <class... Types, class... Args>
auto func(Args... args)
{
  return std::make_tuple(std::make_pair(args, Foo<Types>())...);
}

其中有好的和短的奖励。

答案 1 :(得分:0)

这里的关键数据点是可变参数将与空列表匹配。这有几个后果。

第一个结果是给出以下模板声明:

template <typename Head, typename ...Args, typename Type, typename ...Types>

以及以下实例:

<int, bool, char>

实例化可以通过多种方式匹配模板:

1

Head           int
...Args        bool
Type           char
... Types      (empty list)

2

Head           int
...Args        (empty list)
Type           bool
... Types      char

所以,这是歧义的一个来源。 main()中的引用可以匹配任一模板定义。尽管存在各种神秘的规则,在某些情况下可以解决这种模糊性,但最好不依赖于神秘的模板消歧规则,或者至少采用几种标准的基本SFINAE方法。

但是,回到主题,不管怎么说,编译器将在这里落后于八球,没有明确的候选人来解决main()中的模板参考。但它变得更糟。给定

auto func(Head arg, Args... args)

auto func(Head arg)

因为,variatic参数(在本例中为Args...)可以再次匹配空列表,例如:

func(4)

可以匹配任一功能签名。

将所有这些因素结合在一起,编译器无法真正在这里做出正面或反面。