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

passing template function to std::for_each

本文关键字:std for each 函数      更新时间:2023-10-16

我想写一个简单的模板函数,打印一些容器的每个元素,而不使用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);
});

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

另一个选项:

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

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

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

这提供了许多优点:

  1. 无需在调用现场指定模板类型。
  2. 无需手动类型扣除。
  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;
}