Effective C ++ Item 46: (Please define non-template member function when needed type conversion) of the template and generic programming

A non-member function template error example

  • We have said in terms of 24, for the Rational class, in order to make all the multiplication operations can be accessed through the operation, we will be operator * () function is defined as non-member function version (the details can come back again to see). But for the template, these rules may not hold

  • For example let's put Rational and operator * () function is defined as a template code is as follows:
//下面与条款24都相同,只是改为了模板
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)
{	
}
  • Now we write the following code can not compile. E.g:
Rational<int> oneHalf(1, 2);

//在条款24中,Rational和operator*为非模板,此处代码可编译通过
//此处,Rational和operator*为模板,编译不通过
Rational<int> result = oneHalf * 2;

Error Analysis

  • The reason for this error is: above "oneHalf * 2" No matching operator * () function, resulting in an error
  • the reason:
    • OneHalf type of Rational <int>, so it matches the operator * () function template, and the operator * () function template instance of type T template into int
    • However, when the second operating parameter, when 2 int, operator * () function is a template can not be inferred from an int type T
    • So the final compiler can not find a suitable operator * () function and lead to errors
  • In the non-template operator * () in, operator * () 2 may be an implicit conversion (implicit conversion Rational provides the details and then go to clause 24) as Rational objects. But in the template, the implicit conversion is not allowed
  • taken to derive the template argument decisive factor

Second, the template function declared as friend

  • In the "a", the template class and template functions we use the wrong one, one solution is to operator () * declared as a friend Rational template classes (friend)
  • Let's twice been to modify, and ultimately the wrong code

The first modification (compiler, but wrong link)

  • We first operator () * declared as a friend of Rational . code show as below:
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);


int main()
{
    Rational<int> oneHalf(1, 2);
    //编译通过,但是链接时出错
    Rational<int> result = oneHalf * 2;

    return 0;
}
  • Note: The above friend in life, we do not add in the back Rational <T>, which Rational <T> is the same, both are
  • Compiled by reason of:
    • OneHalf when the object is defined, the program will generate a defined Rational <int> class, then class Rational <int> is instantiated out
    • class Rational <int> After being instantiated, friend operator * () function are automatically declared out (Note: only declared but not defined)
    • After the friend operator * () function is declared out, the function is a function of, rather than a template, so we can be passed to the function 2 (2 implicitly and parameter type conversion, will be converted to 2 Rational)
    • Thus the above code on it by the compiler, but link errors (described below)
  • The reason for the error link:
    • Because the class Rational <int> is instantiated came out, friend just the operator * () statement, but is not defined, so the program error

The Second Amendment (correct version)

  • The above code compile, but the link through, since the definition could not find operator * () of
  • Link error method to solve is: At the same time, the definition of this function in a statement friend function. code show as below:
template<typename T>
class Rational {
public:
    //声明的时候,同时实现该函数(备注,该函数虽然在类中定义,但不属于成员函数)
    friend const Rational operator*(const Rational& lhs, const Rational& rhs)
    {
        return Rational(lhs.numerator()*rhs.numerator(),
        lhs.denominator()*lhs.denominator());
    }
};
  • Another benefit of the friend here: While this function we declare friend, but did not have access to any class of non-public members, so relatively safe

Third, make friend helper function calls (related to the inline)

  • We have said that in terms of 30, if the function is defined in the class will become inline, and therefore the above we define friend operator in the class of () * will be called inline
  • In order to minimize the impact of inline brings, we can:
    • We can not do () * in what operator, will be the complete thing to another auxiliary function
    • The helper should be a template
  • code show as below:

    • In order to make operator * () optimized inline in the class, we define a helper function, in which the complete operator * () is supposed to complete the function

    • doMultiply () does not support hybrid operation (such as an object and an int Rational multiplication), but the function * () is called only by the operator, and the operator * () support the mixing operation, and therefore functional

//声明
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 operator*(const Rational& lhs, const Rational& rhs)
    {
        //在其中调用doMultiply(),可使inline最优化
        return doMultiply(lhs, rhs);
    }
};

//完成原本operator*()要完成的功能
template<typename T>
const Rational<T> doMultiply(const Rational<T>& lhs, const Rational<T>& rhs)
{
    return Rational<T>(lhs.numerator()*rhs.numerator(),
        lhs.denominator()*lhs.denominator());
}

IV Summary

  • When we write a class template, and it provides the "template associated with this" function supports "all the parameters of the implicit type conversion", set those functions defined as "inside the class template friend function"
Released 1525 original articles · won praise 1084 · Views 450,000 +

Guess you like

Origin blog.csdn.net/qq_41453285/article/details/104887321