【问题标题】:C++ Multiple variadic template not binded to function argumentsC++ 多变量模板未绑定到函数参数
【发布时间】:2016-04-02 21:18:41
【问题描述】:

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

#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) 后可以使用多个可变参数模板,我认为这是一个简单的例子,如果有解决方案或标准没有,应该有人更了解我不接受。

感谢您的帮助,

【问题讨论】:

  • 应该推断为什么?你告诉它Head 和 2 个Args 并给出了它们各自的函数参数。 Type 没有在任何地方使用,所以不可能推导出来。

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


【解决方案1】:

将推导的参数放在最后。

... 模板参数是贪婪的——它们会消耗传入的参数,并且不会为以后的模板参数“保存”任何参数。

一旦完成,就会从非模板函数参数中进行推导。

像这样交换:

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

另外,去掉其他的重载,所以func&lt;int,int&gt;(3) 没有歧义。

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

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

它的好处是又好又矮。

【讨论】:

  • 实际上我只需要在 Foo 一种类型上进行模板化,因此第二个版本不起作用。第一个仍然模棱两可。看来它不想解压...Args
  • @yayg 在我的第二个示例中,我只传递Foo 一种类型(一次)... 包扩展适用于表达式。
  • 非常感谢!我不知道这个很棒的功能:D
【解决方案2】:

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

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

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)

因为,再一次,可变参数,在本例中为Args...,可以匹配一个空列表,那么,例如:

func(4)

可以匹配任一函数签名。

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

【讨论】:

    猜你喜欢
    • 2023-03-16
    • 2022-06-14
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    相关资源
    最近更新 更多