2
#include <map>
#include <list>

template < typename K, typename  V>
class LruCache
{
private:
    typedef std::pair< K, V > EntryPair;
    typedef std::list< EntryPair > CacheList;
    typedef std::map< K, CacheList::iterator > CacheMap;

public:
    LruCache(){}
    ~LruCache(){}
};

if I try simply

LruCache cache;

I get the following compilation error:

LruCache.h:17:46: error: type/value mismatch at argument 2 in template parameter list for ‘template<class _Key, class _Tp, class _Compare, class _Alloc> class std::map’
LruCache.h:17:46: error:   expected a type, got ‘LruCache<K, V>::CacheList:: iterator’
LruCache.h:17:46: error: template argument 4 is invalid

However, if I define the class without template types. i.e.

class LruCache
{
private:
    typedef std::pair< int, int > EntryPair;
    typedef std::list< EntryPair > CacheList;
    typedef std::map< int, CacheList::iterator > CacheMap;

public:
    LruCache(){}
    ~LruCache(){}
};

It compiles just fine.

hookenz
  • 36,432
  • 45
  • 177
  • 286

2 Answers2

2

Use typename as:

typedef std::map< K,typename CacheList::iterator > CacheMap;
                   //^^^^^^

Its because iterator is a dependent name on the template argument. Its value depends on CacheList which in turn depends on the T which is in fact a template argument. That is why typename its needed here which tells the compiler that iterator is actually a nested type, not static value.

However, in the second case, its not a dependent name.

Read this detail explanation by Johannes:

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    The compiler does not know if CacheList::iterator is a type or a member. For instance, std::string::npos is a constant member, but std::vector::iterator is a type. Since `CacheList` relies on a template parameter (your K and V) the compiler guesses that CacheList::iterator is a member. Since you know it is a type, you must tell the compiler. – Chris Jun 22 '11 at 01:05
1

Replace this:

typedef std::map< K, CacheList::iterator > CacheMap;

with this:

typedef std::map< K, typename CacheList::iterator > CacheMap;

See this question. Basically, the compiler doesn't know (without knowing the template arguments) whether CacheList::iterator is a type or a value until instantiation time, and it's forbidden from postponing the decision until then, so it assumes that it's a value and you have to give it a "hint" otherwise.

Community
  • 1
  • 1
John Calsbeek
  • 35,947
  • 7
  • 94
  • 101