Effective C + + clause 46

Source: Internet
Author: User

This section provides: Define a non-member function for a template when a type conversion is required

This knowledge is based on article 24, which describes the role of non-member functions in the template class (Non-member function template).
Let's take a look at the core of knowledge described in article 24. Article 24 describes how we can implement implicit conversion of objects of a class under certain conditions.
Let's look at the following code:

**

Example one:

**

#include <iostream>#include <assert.h>using namespace STD;classrational{Private:intnumerator;intdenominator; Public: Rational (intn =0,intD =1): Numerator (n), denominator (d) {assert (denominator! =0); }intGetnumerator ()Const{returnnumerator; }intGetdenominator ()Const{returndenominator; }ConstRationaloperator* (Constrational& r2);};ConstRational Rational::operator* (Constrational& R2) {returnRational ( This->getnumerator () * R2. Getnumerator (), This->getdenominator () * R2. Getdenominator ());}intMain () {Rational A (1,2); Rational B = A *2; Rational C =2A//cannot be compiled.     return 0; }

**

Example two:

**

#include <iostream>#include <assert.h>using namespace STD;classrational{Private:intnumerator;intdenominator; Public: Rational (intn =0,intD =1): Numerator (n), denominator (d) {assert (denominator! =0); }intGetnumerator ()Const{returnnumerator; }intGetdenominator ()Const{returndenominator; }};ConstRationaloperator* (Constrational& R1,Constrational& R2) {returnRational (R1. Getnumerator () * R2. Getnumerator (), R1. Getdenominator () *r2. Getdenominator ());}intMain () {Rational A (1,2); Rational B = A *2; Rational C =2A//by compiling.     return 0; }

We can see from the above two pieces of code that the Non-member member function can achieve mixed operation. In fact, the essence of the function is to make use of the implicit conversion of class objects during compilation. For Rational c = 2 * a; this sentence, if declared as a member function within a class, the compiler compiles 2 * a , because 2 is not an object of a class, so the compiler does not use that member function within the class, and it searches for overloaded functions with no other operator*. If not, the compilation fails. For example two, there is exactly one operator* function. Because the rational class's constructor is the non-explicit type, it supports implicit conversions, so 2 is implicitly converted to the Rational class object and compiled successfully.

However, in the template, to achieve the above functions, but also to consider other issues.
Let's look at the following code:

Template<TypeNameT>classrational{ Public: Rational (Constt& numerator=0,Constt& denominator=1);ConstT numerator ()Const;ConstT Denominator ()Const; ...... };Template<TypeNameT>ConstRational<t>operator*(Constrational<t>& LHS,Constrational<t>& rhs) {...}; rational<int> Onehalf (1,2); rational<int> result=onehalf*2;//error, failed to compile

Let's think about why oneHalf*2 this sentence 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, just imagine that the function template does not exist before the instantiation, the non-existent function how to implement the implicit conversion of the parameter? Let's infer the execution of the generic template function, first of all, the template function is instantiated by its own parameters and then executed after instantiation. However, for this example, the type of the two parameter is one Rational<int> , and the other is 2 that, during compilation, the former can be inferred that the type is the rational of int, which is not inferred because implicit type conversions are never taken into account in the template argument derivation process.

In order for the compiler to pass, we can make the following changes

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

The operator* becomes a friend function of the rational class so that when an Rational<int> object is defined, the operator* template function is actually instantiated, and oneHalf*2 when this sentence is called, it is called directly to the operator* function that has been instantiated. , so at this point, it supports implicit conversions, converting 2 to Rational<int> objects.

It is worth mentioning that the above code can also be written in the following form:

Template<typenameT>class  rational  {public : ... friend const rational  <t  > operator*< Span class= "Hljs-container" > (const  rational  << Span class= "Hljs-type" >t  >& LHS , const  rational  <t  >&        RHS ) ; {return rational  <t  > (lhs.numerator ()  *rhs.numerator () , Lhs.denominator ()  *rhs.denominator () ); }    };

In other words, Rational<T> Rational the form is a meaning, in order to simplify, we can use Rational the form.

Because this defines the friend function in the rational class, it is the inline function inline by default, in order to avoid complex friend functions affecting the volume of code, we use another form of implementation.
The following code:

 Template<TypeNameT>classRational;//forward decelarion    Template<TypeNameT>ConstRational<t> domultiply (Constrational<t>& LHS,Constrational<t>& RHS);Template<TypeNameT>classrational{ Public: ......friend ConstRationaloperator*(Constrational& LHS,Constrational& RHS);//declaration + definition{returnDomultiply (LHS,RHS); }    };Template<TypeNameT>ConstRational<t> domultiply (Constrational<t>& LHS,Constrational<t>& RHS) {returnRational<t> (Lhs.numerator () *rhs.numerator (), Lhs.denominator () *rhs.denominator ()); }

We have redefined a non-class member function Non-member, which puts the declaration and definition of this function outside the class, thus avoiding the problem of code bloat.

Summarize

When writing a class template, which provides the "related to this template" function to support "implicit type conversion of all parameters," define those functions as a friend function inside the class template.

Effective C + + clause 46

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.