如何使集合迭代器的行为像地图迭代器一样?

发布于 2024-10-01 19:17:52 字数 1200 浏览 1 评论 0原文

我有一个类 Foo ,它包含一个 map 并提供 begin()end() 函数进行迭代it:

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 更改为 std::set,但我不这样做想要破坏任何客户端代码。

因此,insert 函数中的 double d 现在将被忽略。以下代码应该仍然有效,其中 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::const_iterator 使其行为像旧的 std::map::const_iterator

更新:我想摆脱map的原因是内存效率。我有数百万个 Foo 实例,无法在其中存储 double 值。

I have a class Foo that contains a map and provides begin() and end() functions to iterate over it:

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; }
  // ...

};

Now I would like to change it internally from std::map<int, double> to just a std::set<int>, but I don't want to break any client code.

So the double d in the insert function would now just be ignored. And the following code should still be valid, where it->second will now just always be 0.0:

Foo foo;
for(Foo::const_iterator it = foo.begin(); it != foo.end(); ++it) {
  std::cout << it->first << " " << it->second << std::endl;
}

How can I make these changes in the Foo class?

In other words, how can I provide a Foo::const_iterator that adapts the new internal std::set<int>::const_iterator to behave like the old std::map<int,double>::const_iterator?

UPDATE: The reason I want to get rid of the map is memory efficiency. I have millions of Foo instances and cannot afford to store the double values in them.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

城歌 2024-10-08 19:17:52

使用

std::set<std::pair<int, double> >

不足以实现这种可比性吗?

如果失败,您始终可以编写自己的迭代器,它包装 std::list 迭代器并提供 firstsecond 成员。基本上你的operator++会在真正的迭代器等上调用operator++,并且取消引用运算符可以返回一个临时的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;
  }

}

Would using

std::set<std::pair<int, double> >

not be sufficient for this comparability?

Failing that you can always write your own iterator which wraps the std::list iterator and provides first and second members. Basically your operator++ would call operator++ on the real iterator etc. and the de-referencing operator could return either a temporary std::pair (by value) or a reference to a std::pair that lives within the iterator itself (if your legacy code can deal with that).

Update, slightly contrived example, might work depending on your scenario:

#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;
  }

}
说谎友 2024-10-08 19:17:52

像这样的事情怎么样?

#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;
}

How about something like this?

#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;
}
云胡 2024-10-08 19:17:52

也许是某种包装内的东西

operator int()(const std::pair<int, double>& p) const {
    return p.first;
}

Perhaps something along the lines of

operator int()(const std::pair<int, double>& p) const {
    return p.first;
}

maybe within some wrapper?

输什么也不输骨气 2024-10-08 19:17:52

也许您可以定义一个实现 firstsecondfake_pair 类,并将 set 放入 中>Foo

Perhaps you can define a fake_pair class that implements first and second and put a set<fake_pair> inside Foo.

隔纱相望 2024-10-08 19:17:52

你不能,不完全。问题是你正在改变你的界面,这总是会破坏你的客户。我建议您创建两个新函数 newBegin 和 newEnd (或类似的),它们具有您的新行为。您的旧界面保持不变,但将其标记为已折旧。这个旧接口的实现可以使用其他人描述的解决方法之一。

You can't, not completely. The problem is you are changing your interface, which will always break your clients. I would recommend you create two new functions of newBegin and newEnd (or similar) which has your new behaviour. Your old interface you keep this the same but mark it as depreciated. The implementation of this old interface can use one of the work around described by the others.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文