考虑以下示例(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<T>
,为什么此代码无法编译?
答案 0 :(得分:4)
模板功能不是功能。它们是用于编写函数的模板。
template <typename T>
void f(S<T>, T) {}
这是一个用于编写类型为T
的函数的模板。
现在,C ++会在某些情况下尝试为您推断T
。它所做的是每个参数上的模式匹配(一次)。
如果任何参数未能找到匹配项,或者推断的类型不一致或不完整,则扣除失败。未尝试转换或部分匹配。如果找到匹配项,则将它们作为候选者添加到考虑的重载中(这里有一些规则),然后重载决策启动。
在超载分辨率下,考虑时间转换。在模板类型扣除时,除了转换为基础之外,它不是。
在您的情况下,S<T>
无法从T
中推断出1
类型。所以演绎完全失败了。我们从未达到过多考虑转换的重载决策。
碰巧你可以阻止在推论中考虑参数:
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) {}
现在你的主要编译。