我有一个包含Foo
的课程map
,并提供begin()
和end()
个函数来迭代它:
class Foo {
typedef std::map<int, double> Container;
typedef Container::const_iterator const_iterator;
Container c_;
public:
const_iterator begin() const { return c_.begin(); }
const_iterator end() const { return c_.end(); }
void insert(int i, double d) { c_[i] = d; }
// ...
};
现在我想在内部从std::map<int, double>
更改为std::set<int>
,但我不想破坏任何客户端代码。
因此double d
函数中的insert
现在只会被忽略。并且以下代码仍然有效,其中it->second
现在只是0.0
:
Foo foo;
for(Foo::const_iterator it = foo.begin(); it != foo.end(); ++it) {
std::cout << it->first << " " << it->second << std::endl;
}
如何在Foo
课程中进行这些更改?
换句话说,我如何提供Foo::const_iterator
以使新内部std::set<int>::const_iterator
的行为与旧版std::map<int,double>::const_iterator
相符?
更新:我想摆脱map
的原因是内存效率。我有数百万Foo
个实例,无法将double
值存储在其中。
答案 0 :(得分:2)
将使用
std::set<std::pair<int, double> >
这种可比性还不够?
如果失败,你总是可以编写自己的迭代器来封装std :: list迭代器并提供first
和second
成员。基本上你的operator ++会在真正的迭代器等上调用operator ++。并且de-referencing运算符可以返回一个临时的std :: pair(按值)或者对一个生成在迭代器本身内的std :: pair的引用(如果你的遗产)代码可以处理那个)。
根据您的情况,更新,稍作设想的示例可能有效:
#include <iostream>
#include <set>
class Foo {
typedef std::set<int> Container;
typedef Container::const_iterator legacy_iterator;
Container c_;
// legacy iterator doesn't have a virtual destructor (probably?), shouldn't
// be a problem for sane usage though
class compat_iterator : public legacy_iterator {
public:
compat_iterator(const legacy_iterator& it) : legacy_iterator(it) {
}
const std::pair<int,double> *operator->() const {
static std::pair<int,double> value;
value = std::make_pair(**this, 0.0);
// Not meeting the usual semantics!
return &value;
}
};
public:
typedef compat_iterator const_iterator;
const_iterator begin() const { return c_.begin(); }
const_iterator end() const { return c_.end(); }
};
int main() {
Foo foo;
for(Foo::const_iterator it = foo.begin(); it != foo.end(); ++it) {
std::cout << it->first << " " << it->second << std::endl;
}
}
答案 1 :(得分:1)
这样的事情怎么样?
#include <iostream>
#include <map>
#include <set>
struct Funky
{
int first;
static const double second;
Funky(int i)
: first(i)
{}
};
const double Funky::second = 0.0;
bool operator<(const Funky& lhs, const Funky& rhs)
{
return lhs.first < rhs.first;
}
class Foo
{
private:
//std::map<int,double> m_data;
std::set<Funky> m_data;
public:
//typedef std::map<int,double>::const_iterator const_iterator;
typedef std::set<Funky>::const_iterator const_iterator;
const_iterator begin() const
{
return m_data.begin();
}
const_iterator end() const
{
return m_data.end();
}
void insert(int i, double d)
{
//m_data.insert(std::make_pair(i, d));
m_data.insert(i);
}
};
int main()
{
Foo foo;
foo.insert(23, 9.0);
for(Foo::const_iterator it=foo.begin(), iend=foo.end(); it!=iend; ++it)
{
std::cout << it->first << ' ' << it->second << '\n';
}
return 0;
}
答案 2 :(得分:0)
或许类似于
operator int()(const std::pair<int, double>& p) const {
return p.first;
}
也许在一些包装内?
答案 3 :(得分:0)
也许您可以定义一个实现fake_pair
和first
的{{1}}类,并将second
放在set<fake_pair>
内。
答案 4 :(得分:0)
你不能,不完全。问题是你正在改变你的界面,这将永远打破你的客户。我建议你创建newBegin和newEnd(或类似)的两个新函数,它们具有你的新行为。您的旧界面保持不变,但将其标记为折旧。这个旧接口的实现可以使用其他人描述的工作之一。