15

I have this code, which works on GCC:

#include <map>

class Foo;
class Bar;

typedef std::map<Foo,Bar> MyMap;

MyMap::iterator i;

class Foo
{
    MyMap::iterator some_data;
};

The code as currently designed (which is unpleasantly circular yes I'm stuck with it) requires map<Foo,Bar>::iterator to be available to Foo and Bar.

It works because the GCC library implementation happens to not need to instantiate the map's key type in order to instantiate the iterator.

Is this guaranteed? The standard seems to be somewhat hands-off when it comes to defining the map iterator type. How portable is this code?

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
spraff
  • 32,570
  • 22
  • 121
  • 229

2 Answers2

3

This results in undefined behavior.

In the declaration MyMap::iterator i;, MyMap is required to be a complete type, thus it is implicitly instantiated. However, Foo and Bar are not complete at this point of instantiation, so the behavior is undefined according to [res.on.functions]/2:

In particular, the effects are undefined in the following cases:

  • ...
  • if an incomplete type ([basic.types]) is used as a template argument when instantiating a template component or evaluating a concept, unless specifically allowed for that component.
xskxzr
  • 12,442
  • 12
  • 37
  • 77
0

You can side-step the entire question by considering the fact that std::map is a node-based container, so that its nodes containing elements have stable addresses. I.e. you can use a plain pointer instead of an iterator (as long as you don't need an iterator to pass into member functions of the std::map, of course):

class Foo
{
    std::pair<Foo const, Bar>* some_data;
};

Note that only declarations for Foo, Bar and std::pair<> are needed here to define member some_data.

If you use boost::multi_index (which is superior to std associative containers in many ways) then it has extremely useful functions to_iterator that takes a reference to the element and returns an iterator to it.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271