Valid C ++ clause 46 and valid clause 46

Source: Internet
Author: User

Valid C ++ clause 46 and valid clause 46

Terms of this section: When type conversion is required, define non-member functions for the template.

This section describes the role of non-member functions in the template class based on Clause 24.
Let's take a look at the core knowledge of Clause 24. Clause 24 describes how we can implement implicit conversion of class objects under certain conditions.
Let's take a look at the following code:

**

Example 1:

**

# Include <iostream> # include <assert. h> using namespace std; class Rational {private: int numerator; int denominator; public: Rational (int n = 0, int d = 1): numerator (n ), denominator (d) {assert (denominator! = 0);} int GetNumerator () const {return numerator;} int GetDenominator () const {return denominator;} const Rational operator * (const Rational & r2 );}; const Rational: operator * (const Rational & r2) {return Rational (this-> GetNumerator () * r2.GetNumerator (), this-> GetDenominator () * r2.GetDenominator ();} int main () {Rational a (1, 2); Rational B = a * 2; Rational c = 2 * a; // compilation fails. Return 0 ;}

**

Example 2:

**

# Include <iostream> # include <assert. h> using namespace std; class Rational {private: int numerator; int denominator; public: Rational (int n = 0, int d = 1): numerator (n ), denominator (d) {assert (denominator! = 0);} int GetNumerator () const {return numerator;} int GetDenominator () const {return denominator ;}}; const Rational operator * (const Rational & r1, const Rational & r2) {return Rational (r1.GetNumerator () * r2.GetNumerator (), r1.GetDenominator () * r2.GetDenominator ();} int main () {Rational a (1, 2 ); rational B = a * 2; Rational c = 2 * a; // compiled. Return 0 ;}

We can see from the above two pieces of code that the non-member function can implement a hybrid operation. In fact, the essence of this function is implemented by implicit conversion of class objects during compilation. ForRational c = 2 * a;If it is declared as a member function in the class, the compiler compiles2 * aBecause 2 is not a class object, the compiler will not use the member function in the class, it will search for any other operator * overload function. If no, the compilation fails. For example 2, there is exactly an operator * function. Because the Rational class constructor is of the non-explicit type and supports implicit conversion, 2 is implicitly converted to the Rational Class Object and compiled successfully.

However, in the template, if you want to implement the above functions, you need to consider other issues.
Let's look at the following code:

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 (); Rational <int> result = oneHalf * 2; // error, cannot be compiled

Let's think about whyoneHalf*2This statement cannot be compiled. In fact, there are two parameters in the operator * template function, so it will match these two parameters to determine the function template type. Imagine that the function template does not exist before it is instantiated, how can a function that does not exist implement implicit conversion of parameters? We can infer the execution process of a general template function. First, the template function is instantiated through its own parameters before being called for execution. However, for this example, one of the two parameter types isRational<int>And the other is2During compilation, the former can be inferred that the type is int rational, but the latter cannot be inferred, because implicit type conversion is never taken into account during the real parameter derivation of the template.

To make compilation pass, we can make the following changes:

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());        }    };

Changes operator * into a Rational class's friend function.Rational<int>The operator * template function is actually instantiated, and then calledoneHalf*2In this case, the instantiated operator * function is called directly. Therefore, it supports implicit conversion and converts 2Rational<int>Object.

It is worth mentioning that the above Code can also be written as follows:

template<typename T>class Rational{    public:        ……        friend const Rational<T> operator*(const Rational<T>& lhs,const Rational<T>& rhs);        {            return Rational<T>(lhs.numerator()*rhs.numerator(),lhs.denominator()*rhs.denominator());        }    };

That is to sayRational<T>AndRationalTo simplify the process, we can useRational.

In this way, the friend functions are defined in the Rational class, which is the inline function by default. To avoid the impact of complicated friend functions on the Code volume, we use another method.
The following code:

Template <typename T> class Rational; // forward decelarion 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); // Declaration + definition {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 ());}

We have redefined a non-class member function non-member, which places the Declaration and definition of this function outside the class, so as to avoid code expansion.

Summary

When you compile a class template, it provides the "template-related" function that supports "implicit type conversion of all parameters, define those functions as the friend functions in the class template.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.