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

passing template function to std::for_each

我正在尝试编写一个简单的模板函数来打印某个容器的每个元素,而不使用 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,但是代码无法编译。我该怎么做?

您可以使用:

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

Tstd::vector<>::iterator 类型,即 RandomAccessIterator。每个 RandomAcessIterator 都有一个基础类型,由 value_type.

公开

因此,如果您传递 std::vector<int>::iteratorstd::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);
});

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

另一个选项:

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

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

这带来了许多优势:

  1. 无需在调用站点指定模板类型。
  2. 无需 fiddle 手动类型推导。
  3. 部分专业化可以通过让仿函数遵循模板化的自由函数来实现。

如:

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