我有以下包装C ++映射的类。我只想覆盖迭代器取消引用,只返回映射的值而不是键。完全有可能,而不必重新实现整个std::map
迭代器(我应该尽可能避免使用它)?
这里是:
#include <map>
using std::map;
class X {
using Type = map<int, double>;
using const_iterator = typename Type::const_iterator;
public:
void insert(int key, double value) {
my_map[key] = value;
}
const_iterator cbegin() const { return my_map.cbegin(); }
const_iterator cend() const { return my_map.cend(); }
const_iterator begin() const { return my_map.cbegin(); }
const_iterator end() const { return my_map.cend(); }
private:
Type my_map;
};
int main() {
X x;
double i;
for (const auto& it : x) {
i = it.second; // works
i = it; // fails
}
}
答案 0 :(得分:1)
您几乎需要实现整个迭代器类型以提供新的迭代器行为。幸运的是,Boost有两个工具可以使此操作变得更加简单:boost::iterator_facade
是用于创建迭代器类型的工具,它可以满足标准定义的各种类型的迭代器的所有需求详细信息。对于常见的情况,您想创建一个包装另一个迭代器的迭代器,仅覆盖其部分功能,这里有boost::iterator_adaptor
。
因此,您可以这样定义X::const_iterator
:
#include <map>
#include <boost/iterator_adaptor.hpp>
using std::map;
class X {
using Type = map<int, double>;
public:
class const_iterator : public boost::iterator_adaptor<
const_iterator, // Derived iterator type, for CRTP
typename Type::const_iterator, // Wrapped iterator type
const double> // Value type
{
public:
const_iterator() {}
private:
// Allow X to create X::const_iterator from Type::const_iterator:
explicit const_iterator(typename Type::const_iterator map_iter)
: iterator_adaptor(map_iter) {}
friend X;
// Define the dereference operation:
const double& dereference() const
{ return base()->second; }
// Allow boost's internals to use dereference():
friend boost::iterator_core_access;
};
const_iterator cbegin() const { return const_iterator(my_map.cbegin()); }
};
...
(我有意将名称X::const_iterator
的访问权限从私有更改为公共。有人可能希望显式命名该迭代器类型。)
答案 1 :(得分:0)
从Yakk的答案here中借用,您可以轻松地对其进行修改以满足您的需求。
template<class T>
T value_of(T t) { return std::move(t); }
template<class K, class V>
V value_of(std::pair<K, V> const& p) { return p.second; }
template<class It>
struct range_t {
It b;
It e;
It begin() const { return b; }
It end() const { return e; }
};
template<class T>
struct value_t {
T t;
void operator++(){ t++; }
auto operator*() { return value_of(*t); }
friend bool operator==(value_t const& left, value_t const& right)
{ return left.t == right.t; }
friend bool operator!=(value_t const& left, value_t const& right)
{ return left.t != right.t; }
};
template<class T>
range_t<value_t<T>> values_over(T b, T e) {
return {{b}, {e}};
}
template<class C>
auto values_of(C& c) {
using std::begin; using std::end;
return values_over(begin(c), end(c));
}
int main() {
X x;
double i;
for (double const& it : values_of(x)) {
i = it;
}
}