codesavesworld
codesavesworld

Reputation: 793

friend operator in nested class of templated class

I want to add a iterator class type for my vector class,and I declare some compare operator as friend function of iterator class.but it didnt complie correctly,I did forward declaration.

template<class object>class vector;
template<class object>
bool operator<(typename vector<object>::const_iterator& lhs, typename vector<object>::const_iterator& rhs);

template<class object>class vector {
protected:
    //some member 
public:
    class const_iterator {
        friend bool operator< <>(const_iterator& lhs, const_iterator& rhs);
        friend bool operator> <>(const_iterator& lhs, const_iterator& rhs);
        //...
    };
};

compiler said no matching overloaded function found,I use vs2019.I guess something wrong with forward declaration.

and another question is,I notice some people use this form when declare friend function inside class.

class myclass{
    friend void foo<T>(T t);
    //...
}

but when declare a operator as friend it's different

friend bool operator< <>(const myclass& lhs, const myclass& rhs);

I wonder what's the difference between these two.

please help me,thanks a lot.

Upvotes: 2

Views: 204

Answers (1)

Evg
Evg

Reputation: 26292

In your forward declaration

template<class object>
bool operator<(typename vector<object>::const_iterator&, 
               typename vector<object>::const_iterator&);

const_iterator is in the non-deduced context, i.e. the compiler will not be able to deduce int for object in the following call:

vector<int>::const_iterator c1;
vector<int>::const_iterator c2;

c1 < c2;

I can suggest two solutions.

  1. The simplest one: omit your forward declarations and provide a definition for operator< inside the body of const_iterator:

    friend bool operator<(const_iterator& lhs, const_iterator& rhs) {
        ... return ... ;        
    }
    
  2. If you can't define operator< inside const_iterator, use CRTP to turn a non-deduced context into a deduced one:

    template<class derived>
    struct const_iterator_crtp {};
    
    template<class derived>
    bool operator<(const_iterator_crtp<derived>&,
                   const_iterator_crtp<derived>&);
    
    template<class object>
    struct vector {
        struct const_iterator : const_iterator_crtp<const_iterator> {
            using base = const_iterator_crtp<const_iterator>;
            friend bool operator< <>(base&, base&);
        private: 
            int priv;
        };
    };
    
    template<class derived>
    bool operator<(const_iterator_crtp<derived>& lhs, 
                   const_iterator_crtp<derived>& rhs)
    {
        auto& l = static_cast<derived&>(lhs);  // these static_cast's are safe
        auto& r = static_cast<derived&>(rhs);
        return l.priv < r.priv;
    }
    

Is the operator< a function template in the first solution? Why we don't need a <> after operator<?

  1. It is not a template. You don't need <> in this definition.

  2. You forward declare a template first. Without <>, a friend declaration introduces a non-template function. A non-template function, even if it has the same name as template one (non-template and template functions can overload!), should be defined somewhere. You'll get a link error without such a definition. To override the default behavior and to refer to the function template that was forward declared earlier, you add <>.

Upvotes: 1

Related Questions