【问题标题】:Calling a function with an argument implicitly convertible to an object of template class使用可隐式转换为模板类对象的参数调用函数
【发布时间】:2017-09-13 02:04:46
【问题描述】:

考虑以下示例 (godbolt):

template <typename T>
struct S {
    S(int) {}
};

template <typename T>
void f(S<T>, T) {}

int main() {
    f(1, 2);
}

编译它会出现以下错误:

<source>: In function 'int main()':
10 : <source>:10:11: error: no matching function for call to 'f(int, int)'
     f(1, 2);
           ^
7 : <source>:7:6: note: candidate: template<class T> void f(S<T>, T)
 void f(S<T>, T) {}
      ^
7 : <source>:7:6: note:   template argument deduction/substitution failed:
10 : <source>:10:11: note:   mismatched types 'S<T>' and 'int'
     f(1, 2);
           ^

S 设为非模板会使示例编译。

尽管从 int 隐式转换为 S&lt;T&gt;,为什么这段代码无法编译?

【问题讨论】:

  • T不能在S&lt;T&gt;中推导出来。这可能看起来很奇怪,但考虑到只存在从intS&lt;float&gt; 的转换的情况,T 应该是什么?
  • 或者S&lt;int&gt; 没有那个构造函数
  • 请注意f&lt;int&gt;(1, 2) compiles fine

标签: c++ templates compiler-errors


【解决方案1】:

模板函数不是函数。它们是编写函数的模板。

template <typename T>
void f(S<T>, T) {}

这是一个给定类型T的函数的模板。

现在,C++ 在某些情况下会尝试为您推导出 T。它的作用是模式匹配每个参数(一次)。

如果任何参数找不到匹配项,或者推导的类型不一致或不完整,则推导失败。不尝试转换或部分匹配。如果找到匹配项,则将它们作为候选添加到考虑的重载中(这里有一些规则),然后重载解析开始。

在重载解决时考虑转换。在模板类型推导不是除了转换为base。

在您的情况下,S&lt;T&gt; 无法从 1 推断出类型 T。所以推论根本就失败了。在考虑转换的情况下,我们永远不会达到重载解决方案。

碰巧你可以阻止一个论点在演绎过程中被考虑:

template<class T>struct tag_t{using type=T;}:
template<class T>using block_deduction=typename tag_t<T>::type;

template <typename T>
void f(block_deduction<S<T>>, T) {}

现在你的主编译了。

【讨论】:

    猜你喜欢
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2017-08-28
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    • 2023-02-21
    相关资源
    最近更新 更多