简体   繁体   English

输出迭代器适配器以计数但不复制

[英]Output iterator adapter to count but not copy

There are various STL algorithms that rely on an output iterator to store the result of the algorithm. 有各种STL算法依赖于输出迭代器来存储算法的结果。

For example, std::set_intersection will store all the common elements between two sorted ranges in an Output iterator that is then post incremented per element outputted. 例如, std::set_intersection将在输出迭代器中存储两个已排序范围之间的所有公共元素,然后根据输出的元素进行后递增。

Sometimes, I am not interested in the actual elements but only the number of output elements. 有时,我对实际元素不感兴趣,只对输出元素的数量感兴趣。 In such cases it is a waste of memory and performance to copy the elements. 在这种情况下,复制元素会浪费内存和性能。 Is there an iterator adapter that I can use to count and avoid the copy of the elements? 是否有一个迭代器适配器,我可以使用它来计算和避免元素的副本? If not can you suggest a generic implementation of such an adapter? 如果没有,你能建议这种适配器的通用实现吗?

Boost's Function Output Iterator can do what you want: Boost的函数输出迭代器可以做你想要的:

std::size_t count = 0u;
int arr[]{0, 1, 2, 3};
std::copy(std::begin(arr), std::end(arr),
    boost::make_function_output_iterator([&](auto const&) { ++count; }));
assert(count == 4u);

The only issue is that you have to declare the count variable outside the iterator, because there's no way to extract the stored function object from a boost::function_output_iterator (and also no way to extract the closure values from a lambda, even if you got past that hurdle). 唯一的问题是你必须在迭代器之外声明count变量,因为没有办法从boost::function_output_iterator提取存储的函数对象(也无法从lambda中提取闭包值,即使你有过了那个障碍)。 If you want to be able to write one-liners, you'll have to write the iterator class yourself, but it's not a huge amount of code; 如果你想能够编写单行代码,你必须自己编写迭代器类,但这不是大量的代码; for example: 例如:

class counting_output_iterator {
public:
  using iterator_category = std::output_iterator_tag;
  using value_type = void;
  using difference_type = void;
  using pointer = void;
  using reference = void;

  std::size_t value = 0u;

  struct output_proxy {
    output_proxy(std::size_t& value) : m_value(value) { }
    template<class T> output_proxy& operator=(T const&) {
      ++m_value;
      return *this;
    }
    std::size_t& m_value;
  };
  output_proxy operator*() { return output_proxy(value); }
  counting_output_iterator& operator++() { return *this; }
  counting_output_iterator& operator++(int) { return *this; }
};

Usage: 用法:

int arr[]{0, 1, 2, 3};
auto const count = std::copy(std::begin(arr), std::end(arr),
    counting_output_iterator{}).value;
assert(count == 4u);

Thanks to a lot of help from @ecatmur answer and comments, I have the following solution, which I invite comments. 感谢@ecatmur回答和评论的大量帮助,我有以下解决方案,我邀请评论。 I had hoped to get the boost::make_function_output_iterator working but it seems that there is a bug in the library which fails to define the assignment operator. 我原本希望得到boost::make_function_output_iterator ,但似乎库中有一个错误,无法定义赋值运算符。

#include <algorithm>
#include <vector>
#include <iostream>
#include <string>
#include <cassert>

class counting_output_iterator 
{
public:  
  counting_output_iterator& operator=(const counting_output_iterator&) { return *this; };
  explicit counting_output_iterator(std::size_t& count) : m_count(count) {}
  template<typename T> void operator=(const T&) {}; //NULL op
  using iterator_category = std::output_iterator_tag;
  using value_type = void;
  using difference_type = void;
  using pointer = void;
  using reference = void;      
  counting_output_iterator& operator*() { return *this; }
  counting_output_iterator& operator++() { ++m_count; return *this; }  
  std::size_t&  m_count;
};

int main(int, char*[])
{   
    std::vector<int> arr{ 1,2,3,4 };
    std::size_t count = 0;  
    std::copy(std::begin(arr), std::end(arr), counting_output_iterator{ count } );
    assert(count == 4u);
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM