Search code examples
c++templatesc++11operator-keywordtypename

Overloading operator== With a Free Function That Takes Templated Iterators


So I am trying to create a function that compares two iterators, but I am unsure how to appropriately use the templates. The class

template<typename Key_T, typename Mapped_T>
class Map{...}

The free function

bool operator==(const Map::Iterator &iter1, const Map::Iterator &iter2) {
return (*(iter1.ref->key) == *(iter2.ref->key)) ? true : false; }

I get this error

error: invalid use of template-name ‘cs540::Map’ without an argument list

Then I tried this

template<typename Key_T, typename Mapped_T>
bool operator==(const Map<Key_T,Mapped_T>::Iterator &iter1, const Map<Key_T,Mapped_T>::Iterator &iter2) {...}

and I get this error

error: need ‘typename’ before ‘cs540::Map<Key_T, 
Mapped_T>::Iterator’ because ‘cs540::Map<Key_T, Mapped_T>’ is a dependent scope

Solution

  • The error message is telling you that you need to tell the compiler that Map<Key_T,Mapped_T>::Iterator is a type, by writing typename in front of it - i.e.,

    template<typename Key_T, typename Mapped_T>
    bool operator==(const typename Map<Key_T,Mapped_T>::Iterator &iter1,
                    const typename Map<Key_T,Mapped_T>::Iterator &iter2) { ...}
    

    See Where and why do I have to put the "template" and "typename" keywords? for an explanation why you need to do this.

    But that's not going to work for you, either. Everything to the left of :: is a non-deduced context; for an operator function template to be usable, the compiler must be able to deduce the template arguments from a call, but it cannot do so when the template parameters only appear in non-deduced contexts. The result is that Key_T and Mapped_T can never be deduced, and the operator== will never be used.

    Your design appears to be something along the lines of

    template<typename Key_T, typename Mapped_T>
    class Map{
        class Iterator {
            // ...
        };
        // ...
    };
    

    The usual approach is to define a non-template friend operator== inside the Iterator definition, i.e.

    template<typename Key_T, typename Mapped_T>
    class Map{
        class Iterator {
            // ...
            friend bool operator==(Iterator iter1, Iterator iter2) {
                 return /* ... */;
            }
        };
        // ...
    };
    

    A possible alternative approach is to make Iterator its own class template outside of Map:

    template<typename Key_T, typename Mapped_T>
    class MapIterator {
        // ...
    };
    
    template<typename Key_T, typename Mapped_T>
    class Map{
        using Iterator = MapIterator<Key_T, Mapped_T>;
    };
    

    and now you can write

    template<typename Key_T, typename Mapped_T>
    bool operator==(MapIterator<Key_T, Mapped_T> iter1, MapIterator<Key_T, Mapped_T> iter2) {
         return /* ... */;
    }
    

    as Key_T and Mapped_T can now be deduced properly.