如何正确实现 -> 和 (*)。这样它们的行为就像 -> 和 (*)。在迭代器中



我想为定制容器的迭代器实现 * 和 -> 运算符。我的代码无法编译。下面是一个"最小非工作示例",它显示了它如何与 std::map 一起工作,但不在我的代码中。

#include <vector>
#include <map>
#include <iostream>
struct thing {
  float f[1];
  typedef std::pair<int,float> key_data;
  struct iterator {
    int pos;
    const float *f;
    key_data operator*() const { return key_data(pos,f[pos]); }
    key_data *operator->() const { return &key_data(pos,f[pos]); }
  };
  iterator begin() const { return {.f = f, .pos = 0}; }
};
template<typename T> void test(T iter) {
  (*iter).second = 1.0; std::cout << (*iter).second;
  iter->second = 2.0; std::cout << iter->second;
}
int main() {
  std::map<int,float> fmap; fmap[0] = 0.0;
  test(fmap.begin());
  std::cout << fmap[0];
  thing f;
  test(f.begin());
  std::cout << f.f[0];
}

我希望这来编译:),并打印122122.编译时的错误消息是:

access.cc:13:43: error: taking the address of a temporary object of type 'key_data'
      (aka 'pair<int, float>') [-Waddress-of-temporary]
    key_data *operator->() const { return &key_data(pos,f[pos]); }
access.cc:20:18: error: expression is not assignable
  (*iter).second = 1.0; std::cout << (*iter).second;

对于第一个:公平地说,std::p air<> 创建了一个无法通过引用返回的临时文件;但是标准库如何做到这一点以允许通常的 -> 语法?

对于第二个:可能我再次尝试分配给临时语法,但我无法猜测正确的语法是什么。

更简单的是直接在迭代器中使用正确的类型:

struct thing {
  float f[1];
  using key_data = std::pair<int,float&>;
  struct iterator {
    key_data data;
    const key_data& operator*() { return data; }
    key_data *operator->() { return &data; }
  };
  iterator begin() { return {{0, f[0] }}; }
};

演示

另一种解决方案是使用包装器,如下所示:

struct pair_wrapper
{
    int &first;
    float& second;
    pair_wrapper* operator->() { return this; }
};
struct thing {
  float f[1];
  typedef std::pair<int,float> key_data;
  struct iterator {
    int pos;
    float *f;
    pair_wrapper operator*() { return pair_wrapper{pos,f[pos]}; }
    pair_wrapper operator->() { return pair_wrapper{pos,f[pos]}; }
  };
  iterator begin() { return {0, f}; }
};

演示

它使用了operator->的"魔术"链。

最新更新