【问题标题】:C++ template deduction is not workingC++模板推导不起作用
【发布时间】:2016-12-22 23:42:10
【问题描述】:

对于以下代码:

#include<functional>
template<typename T>
void f(std::function<void(T)> g) {
}

template<typename T>
void g(T x) {
}

int main() {
   f(&g<int>);
}

C++14 编译器产生错误:

 no matching function for call to 'f(<unresolved overloaded function type>)'
     f(&g<int>);

我很好奇为什么模板参数推导在这里不起作用。 看来,鉴于 g 的参数是 int 类型,我们可以推断 f 的参数是 std::function&lt;void(int)&gt; 类型,因此在 f 中是 T = int。为什么这不会发生?我对解释这一点的 C++ 标准的相关部分感兴趣。 T 是否出现在此处的非推导上下文中?

以下类似代码编译:

#include<vector>
template<typename T>
void f(std::vector<T> vec) { 
}


int main() {
    f(std::vector<int>{});
}

所以不是尖括号创建了非推断上下文。

【问题讨论】:

  • f(std::function&lt;void(int)&gt;(g&lt;int&gt;)); 工作
  • xis,谢谢。实际上, f(&g);也可以。我的问题是我无法根据标准中的内容来解释这些行为。

标签: c++ templates c++14 template-argument-deduction


【解决方案1】:

您的函数需要std::function 类型的参数,但您传递给它的是一个指向函数的指针。 &amp;g&lt;int&gt; 可转换std::function 参数类型,但模板参数推导需要完全匹配([temp.deduct.call]/2,3,4 允许的调整除外),不考虑用户定义的转换。

f(std::function&lt;void(int)&gt;(g&lt;int&gt;)) 会起作用,因为你现在传递的是std::function,所以模板参数推导会成功。

f&lt;int&gt;(&amp;g&lt;int&gt;) 也有效,因为您现在已明确指定 T,它不再参与模板参数推导,并且将尝试用户定义的转换。

【讨论】:

  • 谢谢!这是有道理的!我不认为参数推导需要“精确”匹配。例如,如果我在第二个示例中将“const”添加到 f 参数的类型,它仍然可以编译。所以,我想有一些转换是允许的。
  • @Evgenii.Balai 是的,是的,我简化得太多了 :) 现已修复。
  • @Evgenii.Balai:参数类型中的顶级const 不是函数签名的一部分,因此在这种情况下匹配仍然是精确的。有效的非精确匹配是参考。
【解决方案2】:

&amp;g&lt;int&gt; 的类型是void(*)(int)。因此,编译器会尝试生成一个带有签名 void f&lt;&gt;(void(*)(int)) 的函数,它无法从您的模板中执行此操作。 std::function&lt;void(int)&gt; 类型是完全不同的类型。

在您的类似代码中,对象std::vector&lt;int&gt;{} 的类型为std::vector&lt;int&gt;,因此编译器尝试生成一个函数void f&lt;&gt;(std::vector&lt;int&gt;),它可以通过将T 推断为int 从提供的模板中执行该函数。

当指定f&lt;int&gt; 时,编译器不需要推断类型,因此不能不推断。此外,虽然在推导上下文中不考虑隐式转换,但在非推导上下文中考虑它们。因此,通过显式提供类型并使函数参数成为非推导上下文,您允许编译器使用隐式转换将 std::function&lt;void(int)&gt; 参数初始化为 g&lt;int&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-06
    • 2017-07-03
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    相关资源
    最近更新 更多