Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specialize function for map like containers

Tags:

c++

c++11

I want specialize a function template for vector and map like containers. For vector I can do like below but I don't know how can I have a specialized version of the function that will be used only for map like containers.

#include <iostream>
#include <vector>
#include <map>

using namespace std;

template<typename Iterator>
void print(Iterator begin, Iterator end)
{
    while (begin != end)
    {
        cout << *begin << endl; // compiler error for map like containers
        ++begin;
    }
}

int main()
{
    vector<int> noVec = { 1, 2, 3 };

    print(noVec.begin(), noVec.end());

    map<int, int> nosMap;
    nosMap[0] = 1;
    nosMap[1] = 2;
    nosMap[3] = 3;

    print(nosMap.begin(), nosMap.end());

    return 0;
}

This question is similar but it suggests to use pair in vector which I don't want to do. I know the specialization can be done with SFINAE but don't know what condition to check for. It would be great if I can achieve this with C++ 11 type_traits.

like image 241
Sivachandran Avatar asked Aug 13 '14 06:08

Sivachandran


1 Answers

The value_type of a map is some pair so you could check if the value_type of the iterator is a std::pair or not, e.g.

#include <vector>
#include <map>
#include <iostream>

template <typename> 
struct is_pair : std::false_type 
{ };

template <typename T, typename U>
struct is_pair<std::pair<T, U>> : std::true_type 
{ };



template <typename Iter>
typename std::enable_if<is_pair<typename std::iterator_traits<Iter>::value_type>::value>::type
print(Iter begin, Iter end)
{
  std::cout << "called with map-like" << std::endl;
  for (; begin != end; ++begin)
  {
    std::cout << begin->second;
  }
  std::cout << std::endl;
}

template <typename Iter>
typename std::enable_if<!is_pair<typename std::iterator_traits<Iter>::value_type>::value>::type
print(Iter begin, Iter end)
{
  std::cout << "called with vector-like" << std::endl;
  for (; begin != end; ++begin)
  {
    std::cout << *begin;
  }
  std::cout << std::endl;
}



int main()
{
  std::vector<int> vec { 1, 2, 3 };
  std::map<int, int> map {{0, 0}, {1, 1}, {2, 4}, {3, 9}};

  print(vec.begin(), vec.end());
  print(map.begin(), map.end());
}

which prints

called with vector-like
123
called with map-like
0149
like image 175
MadScientist Avatar answered Oct 16 '22 05:10

MadScientist