ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 条款46:需要类型转换时请为模板定义非成员函数 Define non-member functions inside templates when type conversions are desired. ```cpp template<typename T> class Rational { public: Rational(const T& numerator = 0, const T& denominator = 1); ... }; template<typename T> const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs) { ... } Rational<int> oneHalf(1, 2); Rational<int> result = oneHalf * 2; // 无法通过编译 ``` 这里编译器并不知道具体该调用哪个函数,因为 `operator*` 的第一个参数被声明为 `Rational<T>` ,而传递的实参类型为 `Rational<int>` ,所以 T 一定是 int。但是第二个实参为 int,编译器在 template 实参推导过程中从不将隐式类型转换函数纳入考虑。而解决的办法是在 template class 内的 friend 声明式中指涉某个特定函数: ```cpp template<typename T> class Rational { public: ... friend const Rational operator*(const Rational& lhs, const Rational& rhs); }; template<typename T> const Rational<T> operator*(const Rational<T>& lhs, const Rational& rhs) { ... } ``` 因为当对象 `oneHalf` 被声明为一个 `Rational<int>` 时,`class Rational<int>` 于是被具现化出来,而作为过程的一部分,friend 函数 `operator*` 也就被自动声明出来。 但是这种写法只能通过编译,无法进行连接,因为我们没有提供 `friend const Rational operator*` 的定义式。所以最优的写法是: ```cpp template<typename T> class Rational; template<typename T> const Rational<T> doMultiply(const Rational<T>& lhs, const Rational<T>& rhs); template<typename T> class Rational { public: ... friend const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs) { return doMultiply(lhs, rhs); } }; template<typename T> const Rational<T> doMultiply(const Rational<T>& lhs, const Rational<T>& rhs) { return Rational<T>(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator()); } ```