Item 46: When type conversion is required, non-member functions should be defined in the class template.

Source: Internet
Author: User

Item 46: When type conversion is required, non-member functions should be defined in the class template.

Item 46: Define non-member functions inside templates when type conversions are desired.

As mentioned in Item 24, if all parameters require implicit type conversion, this function should be declared as a non-member function. Item 24 isRationalAndoperator*As shown in the example, this article extends this idea to class templates and function templates. However, in the class template, functions that require implicit conversion of all parameters should be declared as friends and defined in the class template.

Templated Rational

Since it is the promotion of Item 24, we first putRationalAndoperator*Templated. The following code is obtained:

template
  
   class Rational {public:  Rational(const T& numerator = 0, const T& denominator = 1);  const T numerator() const;             const T denominator() const;        };template
   
    const Rational
    
      operator*(const Rational
     
      & lhs, const Rational
      
       & rhs){}
      
     
    
   
  

Item 20 explains whyRationalThe parameter is a constant reference; Item 28 explains whynumerator()The returned value is not a reference; Item 3 explains whynumerator()The returned result isconst.

Template parameter deduction Error

The above code is the result of direct templatification of Item24. It looks perfect, but it is problematic. For example, we have the following calls:

Rational
  
    oneHalf(1, 2);            // OKRational
   
     result = oneHalf * 2;     // Error!
   
  

Why is the second error? Because the compiler cannot export the appropriate template parameters for instantiationRational . The derivation of template parameters includes two parts:

  • AccordingonHalf, Its type isRational , It is easy to know and acceptoneHalfOfoperator* Template parametersTIt should beint;
  • According2The template parameter derivation is not so smooth, the compiler does not know how to instantiateoperator* To make it acceptintType2.

    You may want the compiler2Is derivedRational And then perform implicit conversion. In the compiler, template derivation and function calling are two processes: implicit type conversion occurs in function calling, and the compiler needs to instantiate a function before function calling. In the process of template instantiation, the compiler cannot deduceT.

    Declared as a friend Function

    To let the compiler knowTIn the class templatefriendDeclaration to reference an external function.

    template
        
         class Rational {public:    friend const Rational operator*(const Rational& lhs, const Rational& rhs);};template
         
          const Rational
          
            operator*(const Rational
           
            & lhs, const Rational
            
             & rhs){}
            
           
          
         
        

    InRational Declared infriendNo template parameters addedTThis is a simple method, and it is equivalent:friend const Rational operator*(const Rational & lhs, const Rational & rhs); .

    Because after the class template is instantiated,TAlways known, so thatfriendThe function signature will beRationalTemplate Class declaration. In this way,result = oneHalf * 2The compilation is successful, but the link will fail. Although it is clear in the classfriend operator*However, the compiler does not instantiate the function corresponding to the Declaration. Because the function is declared by ourselves, the compiler assumes that we are obligated to define the function ourselves.

    Define in the class

    Then we are declaringoperator*Directly give a definition:

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

    Such a mixed callresult = oneHalf * 2Finally, you can compile, link, and run the program. The problem here must have been clear:

    1. To support implicit type conversion for all parameters,operator*A non-member function needs to be declared;
    2. To allow the compiler to export template parameters,operator*Must be declared in the class;
    3. The only way to declare a non-member function in a class is to declare itfriend;
    4. When declaring a function, we have the obligation to define the function, so the function definition should also be placed infriendDeclaration. Call helper functions

      Althoughoperator*It can be run successfully, but the function defined in the class definition is an inline function. For details, see Item 30. Ifoperator*The function body becomes very large, so the inline function is no longer suitable. In this case, we canoperator*Call an external auxiliary function:

      template
            
              class Rational;template
             
              const Rational
              
                doMultiply(const Rational
               
                & lhs, const Rational
                
                 & rhs);template
                 
                  class Rational{public: friend Rational
                  
                    operator*(const Rational
                   
                    & lhs, const Rational
                    
                     & rhs){ return doMultiply(lhs, rhs); }};
                    
                   
                  
                 
                
               
              
             
            

      doMultiplyHybrid mode calling is still not supported, howeverdoMultiplyOnlyoperator*Call.operator*The hybrid mode will be compatible, and then unifiedRational Type parameter to calldoMultiply.

Related Article

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.