Перегрузка оператора для составного разыменования и присваивания

С перегрузками операторов C++ можно создать класс, который эмулирует тип указателя, поэтому я экспериментировал с абстрагированием операций чтения с помощью этого подхода.

class FilePointer
{
    FILE* file;
    size_t position;
    FilePointer (FILE* file, size_t position)
    {
        this->file = file;
        this->position = position;
    };
    public:
    FilePointer (FILE* file)
    {
        this->file = file;
        this->position = 0;
    };
    FilePointer operator+ (size_t offset)
    {
        return FilePointer(file,position + offset);
    };
    FilePointer operator++ () // Prefix : ++FilePointer
    {
        position++;
        return *this;
    };
    FilePointer operator++ (int) // Postfix : FilePointer++
    {
        FilePointer before = *this;
        position++;
        return before;
    };
    FilePointer operator+= (size_t offset)
    {
        position += offset;
        return *this;
    };
    uint8_t operator* ()
    {
        fseek(file,position,SEEK_SET);
        Uint8 out;
        fread(&out,1,1,file);
        return out;
    };
    uint8_t operator[] (size_t offset)
    {
        return *(*this + offset);
    };

};

Как видно из приведенного выше фрагмента кода, я смог выяснить, как различать варианты оператора приращения, чтобы данные FILEFilePointer f; и f++ вели себя интуитивно.

Что, если я хочу использовать этот класс для файла пишет? В настоящее время я могу захватить байт ++f и это работает, но если я хочу что-то "установить", т.е. uint8_t something = f[0];, перегрузки как таковые для этого не подойдут.

Помимо того, является ли это «хорошей практикой» (хотя не стесняйтесь взвешивать и это), есть ли способ реализовать это поведение в перегрузках операторов для класса?

uint8_t n = f[0];
n++;
f[0] = n;

Или, что еще интереснее, что-то вроде этого:

f[1]++;

Один из способов, которым я представляю, что это можно сделать, - реализовать еще один класс, который представляет "разыменованный FilePointer", но было любопытно, возможно ли это сделать только с перегрузками в самом классе FilePointer.

К вашему сведению, в идеале ваш FilePointer operator++ () должен возвращать ссылку на *this, а не копию. FilePointer& operator++ (). Так же и с operator +=. Есть очень хорошо сделанный Q / A на stackoverflow. Стоит прочитать.

WhozCraig 28.05.2019 18:38

Возврат прокси — единственный способ сделать это: выражение f[x] будет оцениваться первым и должно оцениваться как что-то, для которого f[x] = 100 или ++f[x] или что-то другое имеет смысл. operator[] не может ничего узнать о выражении, в котором вызывается is (кроме того, является ли f константной ссылкой или чем-то еще)

Useless 28.05.2019 18:39

Вы знаете о эта почта, не так ли?

πάντα ῥεῖ 28.05.2019 18:47

Кажется более практичным добавить управление итератором, а не управление []

bruno 28.05.2019 18:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
87
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

One way I imagine it could be done is by implementing yet another class which represents a "dereferenced FilePointer"

Это почти единственный способ сделать это. Это будет объект «прокси-типа», который может быть преобразован в uint8_t (возможно, неявно в таком случае, хотя в целом я ненавижу неявные преобразования), но также может быть назначен.

Он должен быть построен с помощью FilePointer* и быть friend, чтобы он мог вызывать соответствующую функцию «записи».

Однако это будет немного запутанно, потому что он может очень быстро «зависнуть», писать не в том месте. Вы мог также сохраняете текущую позицию во время создания прокси-объекта и выполняете возврат к этой позиции если, необходимой на момент написания. Но все эти поиски не очень эффективны.

Также чтение по одному байту за раз происходит медленно.

В целом, хотя ваша попытка замечательна, я бы посоветовал не использовать этот подход в целом. Вы можете по крайней мере обернуть FILE* в хороший класс, который сделает fclose за вас, если он выйдет за рамки.

but was curious if it is possible to do with only the overloads in the FilePointer class itself.

Я так не думаю. Все, что вы возвращаете из operator[], нуждается в каком-то магическом состоянии, которое может принимать значение для «установки» и подключения к механизму FILE*. Возврат uint8_t просто никогда не позволит вам сделать это.

@SombreroChicken :P

Lightness Races in Orbit 28.05.2019 19:33

Имеет много смысла, в том числе и о производительности. Обычно я использовал стандартный файловый ввод-вывод C напрямую (поэтому вы видите FILE* в этом классе), и мне было просто любопытно в C++, что потребуется, чтобы полностью абстрагироваться от файлового ввода-вывода, как это. В принципе, я не планирую использовать это в базе производственного кода, но было бы неплохо увидеть, что вам сойдет с рук в языке.

rsethc 29.05.2019 04:23

Другой подход к повышению производительности записи в 1 символ может заключаться в том, что ваш указатель прокси-файла на самом деле является буфером, который каким-то образом собирает ряд назначений, а затем загружает их все в файл при уничтожении.

При использовании прокси-подхода следует помнить, что вызывающая сторона может удерживать несколько ваших прокси-объектов, используя auto или auto&, и пытаться обновлять их не по порядку. Я не думаю, что есть эффективный способ решить эту проблему.

А как же operator --? Хотя в библиотеке С++ есть концепция односторонних итераторов. возможно, итераторы - лучшая метафора?

Конечно, как только вы начнете буферизовать и предоставлять итераторы, вы просто заново изобрели std::fstream ;)

Lightness Races in Orbit 28.05.2019 19:30

@LightnessRacesinOrbit, ты fstream.

Hatted Rooster 28.05.2019 19:37

@LightnessRacesinOrbit Верно, хотя fstream обычно не использует итераторы таким же образом.

Gem Taylor 28.05.2019 19:39

@GemTaylor Конечно, может!

Lightness Races in Orbit 28.05.2019 19:44

Я не особо знаком с fstream, но его использование немного отличается от того, что я имел в виду. Во всяком случае, то, что я собираюсь сделать, это в значительной степени (крайне неэффективная) эмуляция mmap.

rsethc 29.05.2019 04:25

Другие вопросы по теме