Specialize function for carton containers

I want to specialize a function template for vector and map containers. For a vector, I can do as shown below, but I don’t know how I can get a specialized version of a function that will be used only for map 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 suggests using a pair in a vector that I don't want to do. I know that specialization can be done with SFINAE, but I don’t know which condition to check. It would be great if I could achieve this using C ++ 11 type_traits.

+7
c ++ c ++ 11
source share
2 answers

value_type map is some pair, so you can check if value_type iterator is std::pair or not, for example.

 #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 
+9
source share

You do not need to specialize anything. All you have to do is provide operator<< overloaded output operator<< for std::pair , as shown below:

 template<typename T1, typename T2> std::ostream& operator<<(std::ostream &out, std::pair<T1, T2> const &mp) { return (out << "(" << mp.first << ", " << mp.second << ")"); } 

Live demo


edit:

The above solution, however, like @Benjamin Lindley suggested in the comments, may conflict with other operator<< output template overloads for std::pair .

If so, you can also write in your own namespace (e.g. namespace detail ) two template overload functions (e.g. print_elem ), as shown below:

 namespace detail { template<typename T1, typename T2> std::ostream& print_elem(std::ostream &out, std::pair<T1, T2> const &mp) { return (out << "(" << mp.first << ", " << mp.second << ")"); } template<typename T> std::ostream& print_elem(std::ostream &out, T const &elem) { return (out << elem); } } 

and change the template print as follows:

 template<typename Iterator> void print(Iterator begin, Iterator end) { while (begin != end) { detail::print_elem(cout, *begin) << endl; ++begin; } } 

Live demo

+5
source share

All Articles