template<typename T>
class Rational {
public:
Rational(const T& numerator = 0, const T& denominator = 1);
const T numerator() const;
const T denominator() const;
...
};
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; // error! will not compile
because implicit type conversion functions are never considered during template argument deduction.
a friend declaration in a template class can refer to a specific function.
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<T>& rhs) {
...
}
As a declared functions ( not a function template), compiler can use implicit conversion functions.
the code will compile, it won’t link.
that function is only declared inside Rational, not defined there.
template<typename T>
class Rational{
public:
...
friend
const Rational operator*(const Rational& lhs, const Rational& rhs) {
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
};
have the friend call a heper
template<typename T>
class Rational{
public:
...
friend
const Rational operator*(const Rational& lhs, const Rational& rhs) {
return doMultiply(lhs, rhs);
}
};
template<typename T>
const Rational<T> doMultiply(const Rational<T>& lhs, const Rational<T>& rhs) {
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}