Reputation: 119134
I am having trouble using a private std::map variable from within a class template. Can anyone explain why the following (simplified example) does not work, and what I should be doing instead?
#include <iostream>
#include <map>
template <class T>
class Container
{
private:
typedef std::map<long, T> Map;
typedef Map::iterator Iterator; // <-- this is line 10
Map items;
public:
void insert(const long id, const T& item) { items[id] = item; }
void print()
{
for (Iterator iter = items.begin(); iter != items.end(); iter++)
{ std::cout << iter->second << std::endl; }
}
};
int main()
{
Container<int> container;
container.insert(300, 1);
container.insert(200, 2);
container.insert(100, 3);
container.print();
return 0;
}
The resulting error is somewhat cryptic:
t.cpp:10: error: type 'std::map, std::allocator > >' is not derived from type 'Container'
t.cpp:10: error: ISO C++ forbids declaration of 'iterator' with no type
t.cpp:10: error: expected ';' before "Iterator"
Upvotes: 2
Views: 2384
Reputation: 392911
You need to qualify the dependant typename:
typedef typename Map::iterator Iterator;
Rationale: the compiler, at the time of parsing the template, cannot work out whether is a type or a value expression. This is because the names depend on the template argument(s), which are only known at instantiation time.
You have to help the compiler out.
Sidenotes:
MSVC seems to be lax with this rule, as it's template instantiation engine behaves in non-standard ways, and the name lookups aren't done until instantiation time anyway
sometime, dependent member templates need to be qualified as well:
template <typename aTuple> struct ContrivedSample
{
aTuple data;
void foo()
{
auto v = data.template get<0>(); // template required
}
};
Upvotes: 8