专用于容器等地图的功能

时间:2014-08-13 06:23:50

标签: c++ c++11

我想专门设计一个矢量函数模板,并像容器一样映射。对于矢量我可以在下面做,但我不知道如何才能有一个专门用于地图集合的函数版本。

#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问题类似,但它建议在向量中使用对,我不想做。我知道专业化可以通过SFINAE完成,但不知道要检查的条件。如果我能用C ++ 11 type_traits实现这一点,那就太棒了。

2 个答案:

答案 0 :(得分:9)

value_type的{​​{1}}是一对,因此您可以检查迭代器的map是否为value_type,例如。

std::pair

打印

#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());
}

答案 1 :(得分:5)

您不需要专门化任何东西。您所要做的就是为operator<<提供重载输出std::pair,如下例所示:

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


编辑:

但是,评论中建议的@Benjamin Lindley上述解决方案可能会与operator<<的输出std::pair的其他模板重载冲突。

如果是这种情况,您也可以在自己的命名空间(例如namespace detail)中写入两个模板函数重载(例如print_elem),如下例所示:

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);
  }
}

并像下面的示例一样更改您的template print

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

LIVE DEMO