1. How does the compiler decide, on encountering an operator such as the addition operator in the following initialization:
    SomeClass sc;
    int iobj = sc + 3;
    
  2. Overload resolution for overloaded operators follows the usual three-step process:
  3. Function overload resolution is never applied if an operator only has operands of built-in types. For such operands, a built-in operator is guaranteed to be used, even though the operands could be converted to the class type through a constructor or user-defined conversion.
     #include <iostream>
        
     struct SmallInt {
        
        SmallInt(int val) : _val(val) { std::cout << "Called ctor\n"; }
        
        SmallInt operator+( int a ){ std::cout << "Called SmallInt::operator+\n"; return _val+a; }
        
        void showVal(){ std::cout << "val = " << _val << "\n"; }
        
        int _val;
     };
        
     SmallInt operator+ ( const SmallInt& s1, const SmallInt& s2){
        
        std::cout << "Called SmallInt::operator+\n";
        
        return s1._val+s2._val;
     }
        
     int main() {
        
         SmallInt s(1);
         s = 1 + 2; // Calls built-int operator+(int,int)
         s.showVal();
        
         return 0;
     }
    

Candidate Operator Functions

  1. Five sets of candidate operator functions are built for the use of an operator using the operator syntax with an operand of class type.
  2. The set of candidate operator functions is the union of the five sets of candidate functions listed previously.

    Viable Functions

  3. A set of viable operator functions is selected from the set of candidate operator functions by selecting only the operator functions that can be called with the operands specified when the operator is used.
  4. Since arguments and parameters are associated by position within their respective lists, the convention is that the implicit object parameter, if present, is always the first parameter and the implied object argument, if present, is always the first argument.
  5. For non-static member functions, the type of the implicit object parameter is “reference to cv X” where X is the class of which the function is a member and cv is the cv-qualification on the member function declaration.
     #include <iostream>
        
     namespace NS {
        
        class SmallInt {
           // Friend OP
           friend SmallInt operator+( const SmallInt&, double );
           public:
              SmallInt(int val) : _val(val) {
                 std::cout << "Called ctor\n";
              }
              // Member OP
              SmallInt operator+(int);
           private:
              int _val;
        };
        
        SmallInt operator+( const SmallInt& s, double dval ){
           std::cout << "Called ctor A\n";
           return s._val + dval;
        }
        
        // the type of the implied object parameter is SmallInt&
        SmallInt SmallInt::operator+(int ival){
           std::cout << "Called ctor B\n";
           return this->_val + ival;
        }
     }
        
     int main() {
        
         NS::SmallInt s(1);
         NS::SmallInt t  = s + 2.0;
        
         return 0;
     }
    

    Since the type of the implied object parameter is SmallInt&, the member and non-member operator functions can be considered as:

     SmallInt operator+(SmallInt&, int );
     SmallInt operator+(const SmallInt&, double );
    

    For the first argument, the member operator is a better match. For the second argument, non-member function is a better match. Since neither function is strictly better than the other in all arguments, the compiler reports an ambiguity error.

Ambiguity

  1. Providing both conversion functions that perform implicit conversions to built-in types and overloaded operators for the same class type may lead to ambiguities between the overloaded operators and the built-in operators.
  2. User-defined conversions are applied implicitly by the compiler. This may cause built-in opeators to become viable functions for the use of an operator with operands of class types. Conversion functions and nonexplicit constructors should therefore be used judiciously.