首页 > 解决方案 > 模板推演,这符合吗?

问题描述

这段代码似乎不正确,因为我得到了编译器错误。我试图理解为什么:

template <class ... Ts>
struct type_list{};

template <class ... Ts, class T_, class ... Ts_>
auto foo(type_list<Ts...>, Ts&&..., T_&&t, Ts_&&...) {
    return sizeof(T_);
}

int main() {
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
  return 0;
}

clang 产生以下错误:

example.cpp:16:16: error: no matching function for call to 'foo'
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
               ^~~
example.cpp:11:6: note: candidate template ignored: deduced conflicting types for parameter 'Ts'
      (<int> vs. <>)
auto foo(type_list<Ts...>, Ts&&..., T_&&t, Ts_&&...) {

在我看来,在我的调用中Ts应该推断为int(因为这是使第一个论点有效的唯一方法),然后其他所有内容都将被强制执行。为什么这不起作用?

标签: c++c++11templatesvariadic-templates

解决方案


ClangTs从两个相互冲突的来源推导出来:type_list<Ts...>Ts&&.... 因为你调用foowith type_list<int>{}Ts首先推导出为{int}。但是,因为最后一个参数Ts_&&...具有参数包的类型,所以它可以捕获所有内容;在这种情况下,最后两个参数(whileT_&&t传递给5),推导出Ts_{double, int}(和T_as int)。这Ts没有任何论据,所以它被推断为{}

因此,Clang 的错误消息:Ts被推断为{}{int}(<int> vs. <>)在错误消息中)。

请注意,GCC 做的事情不同:

错误:函数'auto foo(type_list,Ts&& ...,T_&&,Ts_&& ...)的参数太少[with Ts = {int}; T_ = 整数;Ts_ = {double, int}]'

它试图保持Ts推断为{int}但仍推断Ts_{double, int},因此无法给出正确数量的参数。

为了进一步解释,请考虑以下内容:

template <class ... Ts>
struct type_list{};

template <class ... Ts>
auto foo(type_list<Ts...>, Ts...) {
    return sizeof...(Ts);
}

int main() {
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
}

Clang 正确地指出了这一点,因为这两个推论是冲突的:

注意:候选模板被忽略:推断参数“Ts”的冲突类型(<int>vs. <int, double, int>

麻烦的是,你不能用另一个参数包捕获 2 个参数,因为如果放在之后(这是你的情况),它会捕获所有东西,或者如果放在之前什么都不会捕获:

template <class ... Ts>
struct type_list{};

template <class... Ts, class... Ts_>
auto foo(type_list<Ts...>, Ts_..., Ts...) {
    return sizeof...(Ts);
}

int main() {
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
}

在这里,Clang 产生了相同的错误消息,因为Ts仍然{int}type_list, 和{int, double, int}通过捕获所有剩余的参数推导出来。

我认为您唯一的选择是以某种方式处理元组或更明确地调用:(在这种情况下foo<int>(type_list<int>{}, 5, 5.0, 3)您可能可以删除type_list)。这样,Ts不再推断:您明确地 make it {int}


推荐阅读