Question

I am trying to share references between a map and another vector as in the following code:

template <typename T>
void f(T& x) {

  std::map<T, vector<int> > mp;
  mp[x] = vector<int>(2, 4);

  vector< pair<T&, int> > v1;

  for (auto& kv : mp) {
    v1.push_back( make_pair(kv.first, 0) );
  }

}

and call this function from another

int x = 2;
f(x);

But this does not compile.

error: no matching function for call to ‘std::vector<std::pair<int&, int>, std::allocator<std::pair<int&, int> > >::push_back(std::pair<int, int>)’
     v1.push_back( make_pair(kv.first, 0) );

Does anybody see why?

EDIT I was able to make things work with

std::reference_wrapper

Here is my current solution.

template <typename T>
void f(T& x) {

  std::map<std::reference_wrapper<T>, vector<int> > mp;
  mp[x] = vector<int>(2, 4);

  vector< pair<T&, int> > v1;

  for (auto& kv : mp) {
    v1.push_back( make_pair( std::ref(kv.first) , 0) );
  }

  v1[0].first = 34;
}

And

int x = 2;
f(x);
cout << x << endl;

prints 34. Do people see any cons with this vs the pointer based approach?

Was it helpful?

Solution

In general you can store std::pair<T&,int> in an std::vector, but you have to insert values correctly. make_pair(x, 0) creates a std::pair<T,int> with no reference.

You can for example use an initializer lists instead:

 v.push_back({x,0});

Another method would be using std::ref:

v.push_back(std::make_pair(std::ref(x),0));

Example:

std::vector<std::pair<int&,int>> v;
int a = 1;
v.push_back({a,a});
v.push_back(std::make_pair(std::ref(a),a));
a = 2;
std::cout << v[0].first << " " << v[0].second << std::endl; // will write "2 1"

However for your purpose it will not work. You should not get references to keys of a std::map. A std::map is a sorted container, you can not just change a key from the outside. This would mess up the inner workings of the std::map.

OTHER TIPS

Because of type mismatch:

vector< pair<T&, int> > v1;   // value_type is pair<int&, int>
//      ^^^^^^^^^^^^^

and

v1.push_back( make_pair(kv.first, 0) );
//            ^^^^^^^^^^^^^^^^^^^^^^      pair<int, int>

A lvalue-reference to int cannot be initialized with an rvalue.

You cannot have a container of references.

A reference must be initialized at the point of declaration, and declaring a container of references implies filling that container later on.

You could use pointers instead. Non (memory) owning pointers are considered valid c++ style.

Second option would be to look into

std::reference_wrapper

If you really want to reference the same object in your map and your vector of pairs, then you'd be better off looking at a pointer based solution. If your original type is stack based then your secondary collection could use a raw pointer - since it does not have ownership of the key object and so should not take any role in retaining or destructing it - to deference it. Although you'll have to be careful about managing the two collections in sync to avoid any dangling pointers.

That said, depending on why you want to do it, if it's a simple int it may not be worth the complexity.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top