输出迭代器适配器计数但不复制
Output iterator adapter to count but not copy
有多种 STL 算法依赖于输出迭代器来存储算法的结果。
例如,std::set_intersection
会将两个排序范围之间的所有公共元素存储在一个输出迭代器中,然后 post 每个输出的元素递增。
有时,我对实际元素不感兴趣,只对输出元素的数量感兴趣。在这种情况下,复制元素会浪费内存和性能。有没有我可以用来计算和避免元素副本的迭代器适配器?如果没有,您能否建议此类适配器的通用实现?
Boost 的 Function Output Iterator 可以为所欲为:
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);
唯一的问题是您必须在迭代器外部声明计数变量,因为无法从 boost::function_output_iterator
中提取存储的函数对象(也无法从中提取闭包值lambda,即使你越过了那个障碍)。如果你想写一行代码,你必须自己写迭代器 class ,但这不是大量的代码;例如:
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; }
};
用法:
int arr[]{0, 1, 2, 3};
auto const count = std::copy(std::begin(arr), std::end(arr),
counting_output_iterator{}).value;
assert(count == 4u);
感谢@ecatmur 的回答和评论的很多帮助,我有以下解决方案,我欢迎评论。我曾希望让 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;
}
有多种 STL 算法依赖于输出迭代器来存储算法的结果。
例如,std::set_intersection
会将两个排序范围之间的所有公共元素存储在一个输出迭代器中,然后 post 每个输出的元素递增。
有时,我对实际元素不感兴趣,只对输出元素的数量感兴趣。在这种情况下,复制元素会浪费内存和性能。有没有我可以用来计算和避免元素副本的迭代器适配器?如果没有,您能否建议此类适配器的通用实现?
Boost 的 Function Output Iterator 可以为所欲为:
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);
唯一的问题是您必须在迭代器外部声明计数变量,因为无法从 boost::function_output_iterator
中提取存储的函数对象(也无法从中提取闭包值lambda,即使你越过了那个障碍)。如果你想写一行代码,你必须自己写迭代器 class ,但这不是大量的代码;例如:
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; }
};
用法:
int arr[]{0, 1, 2, 3};
auto const count = std::copy(std::begin(arr), std::end(arr),
counting_output_iterator{}).value;
assert(count == 4u);
感谢@ecatmur 的回答和评论的很多帮助,我有以下解决方案,我欢迎评论。我曾希望让 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;
}