Как правильно реализовать -> и (*).чтобы они вели себя как -> и (*).в итераторе - PullRequest
0 голосов
/ 07 февраля 2019

Я хотел бы реализовать операторы * и -> для итератора пользовательского контейнера.Мой код не компилируется.Ниже «Минимальный нерабочий пример», который показывает, как он работает с 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 :: pair <> создает временный объект, который не может быть возвращен по ссылке;но как стандартная библиотека делает это, чтобы разрешить обычный -> синтаксис?

Для второго: вероятно, снова я пытаюсь назначить временный, но я не могу угадать, какой правильный синтаксис.

1 Ответ

0 голосов
/ 07 февраля 2019

Проще иметь прямо правильный тип в итераторе:

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->.

...