将模板函数传递给std :: for_each

时间:2016-08-13 18:21:55

标签: c++ templates foreach stl functor

我正在尝试编写一个简单的模板函数,它可以打印某个容器的每个元素,而不使用for循环。到目前为止,我有

#include <iostream>
#include <vector>
#include <algorithm>

template <typename T> void print_with_space(T x){
  std::cout << x << ' ';
}

template <typename T> void print_all(T beg, T end){
  std::for_each(beg, end, print_with_space<int>);
  std::cout << '\n';
}

int main(){
  int a[] = {1, 2, 3};
  std::vector<int> v(a, a+3);
  print_all(v.begin(), v.end());
  return 0;
}

代码编译并运行,但仅仅是因为我将print_with_space<int>放在print_all的实现中。我想明显有print_with_space,但是代码不能编译。我该怎么做?

4 个答案:

答案 0 :(得分:5)

您可以使用:

std::for_each(beg, end, [](const typename T::value_type& value) {
    print_with_space(value);
});

T的类型为std::vector<>::iterator,为RandomAccessIterator。每个RandomAcessIterator都有一个基础类型,由value_type公开。

因此,如果您通过std::vector<int>::iterator,则std::vector<int>::iterator::value_type将是int

现在您已拥有该类型,您可以创建一个lambda,它将在每次迭代时执行。

在C ++ 14中,你甚至可以这样做:

//'auto' automatically deduces the type for you
std::for_each(beg, end, [](const auto& value) {
    print_with_space(value);
});

答案 1 :(得分:1)

C ++ 03的替代方案:

#include <iterator>

template <typename T> void print_all(T beg, T end)
{
  typedef typename std::iterator_traits<T>::value_type val_t;  
  std::for_each(beg, end, print_with_space<val_t>);
  std::cout << '\n';
}

答案 2 :(得分:1)

另一种选择:

template <typename T> void print_all(T beg, T end) {
    std::for_each(beg, end, print_with_space<decltype(*beg)>);
    std::cout << '\n';
}

答案 3 :(得分:1)

最灵活的解决方案,适用于所有版本的c ++,是使print_with_space成为一个函数对象。

这带来了许多好处:

  1. 无需在呼叫站点指定模板类型。
  2. 无需摆弄手动型扣除。
  3. 可以通过使仿函数遵循模板化的自由函数来实现部分特化。
  4. 如:

    #include <iostream>
    #include <iomanip>
    #include <vector>
    #include <algorithm>
    
    // basic implementation
    template<class T> void impl_print_with_space(const T& x)
    {
        std::cout << x << ' ';
    }
    
    // what about special handling for strings?
    
    template<class C, class Ch, class Alloc>
    void impl_print_with_space(const std::basic_string<C, Ch, Alloc>& x)
    {
        std::cout << std::quoted(x) << ' ';
    }
    
    // functor
    
    struct print_with_space
    {
      template<class T> void operator()(const T& x) const
      {
        impl_print_with_space(x);
      }
    };
    
    
    template <typename Iter> void print_all(Iter beg, Iter end)
    {
      std::for_each(beg, end, print_with_space());
      std::cout << '\n';
    }
    
    int main(){
      int a[] = {1, 2, 3};
      std::vector<int> v(a, a+3);
      print_all(v.begin(), v.end());
    
      auto b = std::vector<std::string> { "hello", "world" };
      print_all(b.begin(), b.end());
    
      return 0;
    }