Search code examples
c++templatesvectorfriend

What is the right way to write friend function declarations in template class?


I'm trying to write my own vector template class, but I have some problems when writing friend function declarations.

At first I wrote like this:

template <typename T, typename Alloc = std::allocator<T>>
class vector {
public:
    friend bool operator==(const vector<T, Alloc>&, const vector<T, Alloc>&);
};

But the compiler reports a warning that I declare a non-template function. So I changed the friend declaration to this:

template <typename T, typename Alloc = std::allocator<T>>
class vector {
public:
    template <typename E, typename F>
    friend bool operator==(const vector<E, F>&, const vector<E, F>&);
};

So far everything is fine, but I think there are still problems. If I write like that, I make all operator== functions which take two template arguments as its friend functions. For example, operator==(const vector<int>&, const vector<int>&) and operator==(const vector<double>&, const vector<double>&) would both be vector<int>'s friend function.

What is the right way to write friend functions in template class?


Solution

  • Friend non-template function

    But the compiler reports a warning that I declare a non-template function.

    Yes, you're declaring a non-template function inside the class definition. That means if you define it out of the class definition, you have to define it as non-template function, and for all the possible instantiations , like:

    bool operator==(const vector<int>& v1, const vector<int>& v2)
    {
        ...
    }
    bool operator==(const vector<char>& v1, const vector<char>& v2)
    {
        ...
    }
    

    That is ugly, you can define it inside the class definition like

    template <typename T, typename Alloc = std::allocator<T>>
    class vector {
    public:
        friend bool operator==(const vector<T, Alloc>&, const vector<T, Alloc>&) {
            ...
        }
    };
    

    Friend function template

    If you want to define it as template function, and constrain the scope of friendship, you can

    // forward declaration
    template <typename T, typename Alloc>
    class vector;
    
    // forward declaration
    template <typename T, typename Alloc>
    bool operator==(const vector<T, Alloc>& v1, const vector<T, Alloc>& v2);
    
    template <typename T, typename Alloc = std::allocator<T>>
    class vector {
    private:
        int i;
    public:
        // only the instantiation of operator== with template parameter type of current T and Alloc becomes friend
        friend bool operator==<>(const vector<T, Alloc>& v1, const vector<T, Alloc>& v2);
    };
    
    template <typename T, typename Alloc = std::allocator<T>>
    bool operator==(const vector<T, Alloc>& v1, const vector<T, Alloc>& v2)
    {
        ...
    }
    

    Then, for vector<int>, only bool operator==(const vector<int>&, const vector<int>&) is friend, other instantiations like bool operator==(const vector<double>&, const vector<double>&) is not.

    LIVE