Search code examples
c++c++11vectorstlreference-wrapper

Pass vector<reference_wrapper<int> > to vector<int>?


I have a large std::vector<int> a, but I would like to work only on a subset of it. The idea was to create a std::vector<reference_wrapper<int> > refa that only contains the said subset (in the mwe, all elements 1< a < 4). I would then like to pass refa to functions that expect a std::vector<int> or std::vector<int>& as arguments (because I also want to use them with a). a can be pretty large and I want to avoid to do the selection multiple times.

Questions

How do I properly pass refa to the functions? What I want is bar(refa) and foobar(refa) to work.

Is there a better way to solve the problem, without changing the functions (too much)?

Code

#include <functional>
#include <iostream>
#include <vector>


int foo(int &a)
{
  a++;
  return 0;
}

int bar(std::vector<int> &va)
{
  for(auto &vaa : va)
    vaa++;

  return 0;
}

int foobar(std::vector<int> va)
{
  for(auto &vaa : va)
    vaa++;

  return 0;
}



int main()
{
  std::vector<int> a= {1, 2, 3, 4, 5};
  std::vector<std::reference_wrapper<int> > refa;

  //Fill refa
  for(auto &aa : a)
    {
      if(aa>1 && aa<4) refa.push_back(std::ref(aa));
    }


  //works
  // for(auto &aa : refa)
  //   aa++;

  //works
  //  bar(a);

  //works, a unchanged
  //  foobar(a);

  //works
  // for(auto &aa : refa)
  //   foo(aa);

  //works                         
  // for(int &aa : refa)
  //  foo(aa)

  // does not work
  // conversion from vector<reference_wrapper<int> > to vector<int>& or vector<int> required
  bar(refa);
  //  foobar(refa);


  for(auto &aa : a)
    std::cout << aa << std::endl;


  return 0;
}

Note int is only used here to keep the example simple.


Solution

  • I would definitely use iterators especially considering your problem ahead (work on a subset of a vector):

    template<class Iterator>
    int bar(Iterator begin, Iterator end)
    {
        for (auto it = begin; it != end; ++it)
            (*it)++;
        return 0;
    }
    

    So that not only you abstract away from the container, but you can also easily pass different iterators from the classical "begin" and "end" iterator to simulate specific ranges:

    bar(a.begin() + 2, a.begin() + 4);
    

    For example, with the above code you will visit elements from 1 to 4 (both excluded). And here's the live example.