0

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
Praetorian
  • 106,671
  • 19
  • 240
  • 328
hootis
  • 103
  • 1

1 Answers1

3

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.

Community
  • 1
  • 1
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Thanks so much. You really cleared my understanding of typename up. I was going to implement as a member function, but the assignment prefers to have a free function, although its seems something is off because we are required to have Iterator inside of Map which means it won't work as you stated. I will try implementing it as a friend function. – hootis Mar 18 '15 at 06:18
  • Nice. A non-nested iterator class and passing by value are good improvements. – Potatoswatter Mar 18 '15 at 06:23
  • @Potatoswatter for what ever reason we have to pass Iterator by reference and have a nested Iterator class. :/ – hootis Mar 18 '15 at 06:25