1

I have 2 pieces of code that look similar and I want to make use of templates to prevent copied code.

if(!myVector.empty()) {
    for(auto& i : myVector)
    {
        std::cout << i << std::endl;
        //some other code that is similar to below
   }
}

if(!myUnorederedMap.empty()) {
    for(auto i : myUnorderedMap)
    {
        std::cout << i.second << std::endl;
        //some other code that is similar to top
    }
}

How do I write a function template for the iterators when I have to call .second on my map but not my vector?

Mozbi
  • 1,399
  • 1
  • 17
  • 25
  • write two template functions which take iterator as input. – billz Jul 16 '14 at 03:35
  • There are function templates in the standard library already (std::copy and std::transform with a [`select2nd`](http://stackoverflow.com/a/5218792/179910)) but they're longer and arguably more repetitive than the loops you've already written. – Jerry Coffin Jul 16 '14 at 04:12

1 Answers1

6
template <typename T>
T const& getValue(T const& t)
{
   return t;
}

template <typename T, typename U>
U const& getValue(std::pair<T, U> const& p)
{
   return p.second;
}


template <typename Container>
void foo(Container const& container)
{
   if(!container.empty()) {
      for(const auto& i : container)
      {
        std::cout << getValue(i) << std::endl;
      }
   }
}

Although, the line if(!container.empty()) does not seem to serve any purpose. You can just as well write:

template <typename Container>
void foo(Container const& container)
{
   for(const auto& i : container)
   {
     std::cout << getValue(i) << std::endl;
   }
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 2
    It should to be `const auto &i` – Slava Jul 16 '14 at 03:44
  • 2
    @RSahu Works with `auto&` *most of the time*. Try passing a `vector` to `foo()`. – Praetorian Jul 16 '14 at 03:54
  • `const auto&`could enable some optimizations (but in this simple case, most probably the compiler would optimize the same with const and without const), by always is better as less access as necessary (and in complex cases could be beneficial to optimizations). – NetVipeC Jul 16 '14 at 04:04
  • @Praetorian Thanks. And what would happen if it wasn't const auto when passing vector? – Mozbi Jul 16 '14 at 04:28
  • 1
    @Mozbi: I think they are referring to the fact that vector returns a proxy class called something like `reference_wrapper` (I forgot) but it is a huge pain in the butt, and everybody agrees that it was a mistake to invent that exception in the standard in the first place. but for backward compatibility reasons, it still exists today, and we need to care (and fear) about this case. – v.oddou Jul 16 '14 at 05:18
  • 2
    @Mozbi `vector` is a specialization of `vector` and dereferencing a `vector::iterator` returns a proxy object that represents a single boolean. Since this proxy object is returned by value, it cannot be bound to a non-const lvalue reference. That's why using `auto&` fails in that case. The rule of thumb I follow for a range based `for` is that if I want to modify the objects being iterated I use `auto&&`, otherwise I use `auto const&` – Praetorian Jul 16 '14 at 06:12