Class 模板忽略了用户定义的转换运算符(非模板则不然)
User-Defined Conversion Operator Ignored for Class Template (Not So for Non-templates)
这段代码确实可以编译(重要的一点是 F()
只接受 A
s,并且由于存在从 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 上的等效错误):
error: no matching function for call to ‘F(B<int>)’
(附加信息表明存在 F(A<>)
但 B
不继承自 A
。)
郑重声明,在 A
中实现隐式转换运算符也无济于事。
为什么模板版本编译不通过?我错过了什么吗?或者实际上没有办法用 class 模板来做?!
(注意:我知道我可以在调用站点将 B
显式转换为 A
;这不是我喜欢的。)
Template argument deduction 不考虑隐式转换。
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
必须首先推导模板参数T
(在重载决议之前),但给定参数A<T>
和参数B<int>
,T
不能推导从中推导出来;然后编译失败。
作为解决方法,您可以像您所说的那样使用显式转换,或者显式指定模板参数。
F<int>(B<int>());
正如 songyuanyao 所解释的那样,模板参数 T
必须先推导。
你可以解决解释T
类型的问题
F<int>(B<int>());
但我知道这可能很烦人。
因此,作为解决您的问题的方法,我建议在调用 F()
之前推导出 T
的另一个模板函数
template <template <typename> class C, typename T>
void G (C<T> const & c)
{ F<T>(c); }
因此您可以调用 F()
,通过 G()
,无需解释 T
类型
G(B<int>{});
这段代码确实可以编译(重要的一点是 F()
只接受 A
s,并且由于存在从 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 上的等效错误):
error: no matching function for call to ‘F(B<int>)’
(附加信息表明存在 F(A<>)
但 B
不继承自 A
。)
郑重声明,在 A
中实现隐式转换运算符也无济于事。
为什么模板版本编译不通过?我错过了什么吗?或者实际上没有办法用 class 模板来做?!
(注意:我知道我可以在调用站点将 B
显式转换为 A
;这不是我喜欢的。)
Template argument deduction 不考虑隐式转换。
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
必须首先推导模板参数T
(在重载决议之前),但给定参数A<T>
和参数B<int>
,T
不能推导从中推导出来;然后编译失败。
作为解决方法,您可以像您所说的那样使用显式转换,或者显式指定模板参数。
F<int>(B<int>());
正如 songyuanyao 所解释的那样,模板参数 T
必须先推导。
你可以解决解释T
类型的问题
F<int>(B<int>());
但我知道这可能很烦人。
因此,作为解决您的问题的方法,我建议在调用 F()
T
的另一个模板函数
template <template <typename> class C, typename T>
void G (C<T> const & c)
{ F<T>(c); }
因此您可以调用 F()
,通过 G()
,无需解释 T
类型
G(B<int>{});