此代码确实可以编译(重要的一点是F()
仅接受A
,并且由于存在从B
到A
的隐式转换,因此我可以轻松地将B
传递给它。)
struct A {};
struct B {
constexpr operator A () const {return {};}
};
void F (A a) {}
int main() {
F(B());
return 0;
}
但是模板版本无法编译:
template <typename T>
struct A {};
template <typename T>
struct B {
constexpr operator A<T> () const {return {};}
};
template <typename T>
void F (A<T> a) {}
int main() {
F(B<int>());
return 0;
}
在GCC上出现以下错误(在MSVC上等效):
错误:没有匹配的函数可以调用“ F(B
)”
(还有其他信息,即有F(A<>)
,但B
并不继承自A
。)
为了记录,在A
中实现隐式转换运算符也无济于事。
为什么模板版本不编译?我想念什么吗?还是实际上没有办法使用类模板呢?!
(注意:我知道我可以在呼叫站点将B
强制转换为A
;这不是我喜欢的。)
答案 0 :(得分:3)
Template argument deduction不考虑隐式转换。
类型推导不考虑隐式转换(上面列出的类型调整除外):这是超载解析的工作,稍后会发生。
必须首先推导模板参数<section>
(在重载解析之前),但是给定参数<span>
的参数T
,则不能推导A<T>
他们;然后编译失败。
作为解决方法,您可以按照说明使用显式转换,也可以显式指定模板参数。
B<int>
答案 1 :(得分:3)
正如Songyuanyao更好地解释的那样,必须在之前推导模板参数T
。
您可以解决重复T
类型的问题
F<int>(B<int>());
但我知道这很烦人。
因此,作为解决您问题的方法,我提出了另一个模板函数,该模板函数在调用T
之前推导F()
template <template <typename> class C, typename T>
void G (C<T> const & c)
{ F<T>(c); }
因此您可以通过F()
来呼叫G()
,而不必重复T
类型
G(B<int>{});