【发布时间】:2010-09-05 06:17:56
【问题描述】:
我在周末再次使用 C++ 并注意到一些我不确定它来自哪里的东西。
Following the advice in this thread,我决定实现一个map_keys_iterator 和map_values_iterator。我采取了 - 我认为 - 推荐的方法,即从 std::map<K,V>::iterator 派生一个类并这样实现它:
template <typename K, typename V>
struct map_values_iterator:
public std::map<K,V>::iterator {
// explicitly call base's constructor
typedef typename std::map<K,V>::iterator mIterator;
map_values_iterator (const mIterator& mi) :
mIterator(mi) {};
const V& operator* () const { return (*this)->second; }
};
到目前为止,一切顺利,以下代码有效(nvm Unicode,我默认使用支持 i18n 的终端):
typedef std::map<double,string> Map;
Map constants;
constants[M_PI] = "π";
constants[(1+sqrt(5))/2] = "φ";
constants[exp(M_PI)-M_PI] = "fake_20";
// ... fill map with more constants!
map_values_iterator<double, std::string> vs(constants.begin());
for (; vs != m.end(); ++vs) {
cout<< (vs != m.begin() ? ", " : "")<< *vs;
}
cout<< endl;
这段代码打印出预期的结果,类似于(因为地图的元素是有序的):
..., φ, ..., π, ...., fake_20, ....
所以我猜map_keys_iterator 也会以类似的方式工作。我注意到 Map 的 value_type 实际上是 pair<const K, V>,所以 keys 版本会返回一个值。
然而,必须声明迭代器的类型很笨拙,所以我想用经典的make_pair-like 习惯用法创建一个调用者。这就是麻烦开始的地方:
template <typename K, typename V>
map_values_iterator<K,V> map_values(const typename std::map<K,V>::iterator &i) {
return lpp::map_values_iterator<K,V> (i);
}
template <typename K, typename V>
map_values_iterator<K,V> map_values(const typename std::map<K,V>::const_iterator &i) {
return lpp::map_values_iterator<K,V> (i);
}
我比较确定这个函数有正确的签名和构造函数调用。但是,如果我尝试从代码中调用该函数:
auto vs= map_values(constants.begin());
我得到一个单一的 STL 编译器错误,格式如下:
error: no matching function for call to ‘map_values(std::_Rb_tree_iterator<std::pair<const double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)’
我在这里假设在这种特殊情况下,整个_Rb_tree_iterator 实际上是正确的迭代器,map::iterator 是对其进行类型定义的;不过我不完全确定。我尝试提供更多重载以查看其中一个是否匹配(删除引用、删除 const、仅使用 non-const_iterator 变体等),但到目前为止,没有任何东西允许我感兴趣的签名。
如果我在调用函数之前将基本迭代器存储在变量中(如auto begin= constans.begin(); auto vs= map_values(begin);),我会得到完全相同的基本错误,只有不匹配调用的描述明显不同(因为它是“const blah& ")。
我第一次尝试实现这种迭代器是通过创建一个聚合 map::iterator 而不是继承的基类,并派生两个类,每个类都有足够的operator*,但该版本遇到的问题比上面,仍然迫使我复制太多的界面。所以我尝试了这个选项进行代码探险。
我试图寻找这个问题的答案,但我的 Google-fu 今天不是很强大。也许我遗漏了一些明显的东西,也许我忘记了推导的东西(尽管我几乎可以肯定我没有——迭代器不像容器),也许我实际上需要为地图指定所有模板参数,或者也许我的编译器坏了,但不管它是什么,我都找不到它,而且我很难理解编译器在这里抱怨的实际是什么。根据我之前的经验,如果您对 STL 做错了什么,您应该会看到大量错误,而不仅仅是 一个(这不是 STL 启动)。
所以...任何(封装良好的)指针都会受到赞赏。
【问题讨论】:
-
你需要使用你自己的实现吗(你有什么自定义的吗?)因为如果这个网站上还没有一个(我想我可能已经看到了),我应该有使用 boost::iterator_adaptor 的 map_key_iterator 的实现(非常基本),它可能会起作用。我在自动转换(到普通 map_iterator)时遇到了一些问题,我无法使用当前的 c++ 解决,所以我没有费心完全完成它,但如果你认为它可能会让你感兴趣,我可以尝试发布代码。
-
不,我当然不需要我的 自己的 实现,但它可以作为练习(我已经离开 C++ 大约 4 年了)并且是一个很好的通用的东西放在自己的工具箱中(Pavel 在下面给出了关键提示)——特别是对于 Boost 不可用的情况。
标签: c++ templates map iterator