我编写了一个包装迭代器的类,并根据需要返回转换后的值:
// iterator-wrapper.h
template<class Iter, class Val, class Fct>
class IteratorWrapper {
Iter cur_;
const Iter last_;
const Fct fct_;
public:
IteratorWrapper(Iter first, Iter last, const Fct fct)
: cur_(first), last_(last), fct_(fct)
{}
const Val Value() const {return fct_(*cur_);}
void Next() {++cur_;}
bool Done() const {return cur_ == last_;}
};
现在,类可以使用它来通过其数据的某些函数返回迭代器:
// mydata.h
#include <map>
#include "iterator-wrapper.h"
class MyData {
struct GetFirst {
template<class T1, class T2>
const T1& operator()(const std::pair<T1,T2>& aPair) const {
return aPair.first;
}
};
struct GetSecond {
template<class T1, class T2>
const T2& operator()(const std::pair<T1,T2>& aPair) const {
return aPair.second;
}
};
typedef std::string Key;
typedef int Val;
typedef std::map<Key, Val> Map;
typedef Map::const_iterator MapIter;
Map m_;
public:
typedef IteratorWrapper<MapIter, Key, GetFirst> KeysIter;
typedef IteratorWrapper<MapIter, Val, GetSecond> ValuesIter;
MyData() { // add some data
m_["foo"] = 1;
m_["bar"] = 2;
}
KeysIter GetKeys() const {
return KeysIter(m_.begin(), m_.end(), GetFirst());
}
ValuesIter GetValues() const {
return ValuesIter(m_.begin(), m_.end(), GetSecond());
}
};
以下是一个示例用法:
#include <iostream>
#include "iterator-wrapper-data.h"
int main() {
MyData d;
std::cout << "KEYS:" << std::endl;
MyData::KeysIter kit = d.GetKeys();
for(; !kit.Done(); kit.Next()){
std::cout << kit.Value() << std::endl;
}
std::cout << "VALUES:" << std::endl;
MyData::ValuesIter vit = d.GetValues();
for(; !vit.Done(); vit.Next()){
std::cout << vit.Value() << std::endl;
}
return 0;
}
我有几个问题:
这是一个合理的设计,还是可以更简洁地进行,也许使用STL或增强功能? (我知道有一个boost::iterator_facade
,但我发现代码的方式比必要的更复杂,我不确定它是否完全符合我的要求。)
为什么std::map
不包含类似的内容(我的意思是keys()
函数返回键上的迭代器等)? (或者是吗?)
返回引用有什么问题,例如const Val& Value() const
(而不是像上面的第一个清单那样按值返回)?
答案 0 :(得分:4)
通过看看boost :: iterator_facade,你走在正确的轨道上,但是你用boost::transform_iterator做得更好。
答案 1 :(得分:2)
关于你的第二个问题:Boost RangeEx库(zip file)(尚未随Boost一起发布但未来包含)将包含用于迭代地图键和值的范围适配器:
int main() {
std::map<int, std::string> m;
m[1] = "one";
m[2] = "two";
std::cout << "KEYS:" << std::endl;
BOOST_FOREACH(int k, m | boost::adaptors::map_keys) {
std::cout << k << std::endl;
}
std::cout << "VALUES:" << std::endl;
BOOST_FOREACH(std::string const & v, m | boost::adaptors::map_values) {
std::cout << v << std::endl;
}
return 0;
}
答案 2 :(得分:1)
这对我来说似乎并不合理,但我认为这不是必要的。来自SGI STL Guide:
的select1st和select2ndint main()
{
map<int, double> M;
M[1] = 0.3;
M[47] = 0.8;
M[33] = 0.1;
transform(M.begin(), M.end(), ostream_iterator<int>(cout, " "),
select1st<map<int, double>::value_type>());
// The output is 1 33 47.
}
哦,当然,还有compose1和compose2,当你想要做的不仅仅是直接将它们提供给某些插入或输出迭代器时。