Как сделать начальную и конечную функции rvalue квалифицированными

Я пишу анализатор файлов. Поскольку пользователь может пройти через файл только один раз, я хочу, чтобы итератор был доступен только из ссылки rvalue.

MyParser parser("/path/to/file");
for(auto it : std::move(parser)){
   // example
   for(auto & [key, value]: it){
      std::court << key << '\t' << value << std::endl;
   }
}

Итак, я сделал следующее

class MyParser{

public:
  MaParser(const std::string &path): begin_iterator_(path){}


  //  ====== Begin   iterator class ==============
  class iterator{
    public:
      typedef std::map<std::string, std::string> value_type;

      // Ctor
      iterator(const std::string & path):{
        // Initialize
      }

      // Default ctor
      iterator() = default;
      
      // Move ctor
      iterator(iterator && other){
        istream_ = std::move(other.istream_);
        values_ = std::move(other.value_);
      }

      iterator & operator=(iterator && other){
        istream_ = std::move(other.istream_);
        values_ = std::move(other.value_);
        return *this;
      }

      void operator++(){// definition}

      value_type & operator*(){
        return value_;
      }    
      
      bool operator==(const iterator & other) const {
        return false; // logic here
      }

      bool operator!=(const iterator & other) const {
        return !(*this == other);
      }

    private:
      std::unique_ptr<std::istream> istream_;
      value_type value_;        
  };
    //  ====== End   iterator class ==============

  iterator && begin() &&{
    return std::move(begin_iterator_);
  }

  iterator && end() && {
    return iterator();
  }
private:
  iterator begin_iterator_;
};

Теперь я могу повторять так:

for(auto it = std::move(parser).begin(); it != myParser::iterator(); ++it){

}

но когда я пытаюсь повторить в соответствии с первоначальным намерением, я получаю сообщение об ошибке

cannot convert 'this' pointer from 'MyParser' to 'MyParser &&'.

Q1: Как решить эту проблему?

Q2: Если вместо begin_iterator в функции begin сделать

iterator && begin() &&{
    return iterator(path_); // Assuming we stored the path in a local variable.
  }

программа вылетает на итераторе init auto it = std::move(parser).begin(); при попытке переместить значение_ в конструкторе перемещения. Почему?

[OT]: в "for(auto it : std::move(parser))" имя it вводит в заблуждение, это не итератор (похоже, это пара, поэтому p было бы лучше)

Jarod42 24.11.2022 15:59

Вы можете поиграть с категорией итератора через std::iterator_traits.

Jarod42 24.11.2022 16:04
Стоит ли изучать 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
2
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Основанный на диапазоне for - это в основном синтаксический сахар. Ваша петля:

for (auto it : std::move(parser)) {
    statements;
}

эквивалентно:

{
    auto && __range = std::move(parser);
    for (auto __begin = __range.begin(), end = __range.end(); __begin != __end; ++__begin) {
        auto it = *__begin;
        {
            statements;
        }
    }
}

Таким образом, хотя __range является ссылкой на rvalue, __range.begin() по-прежнему вызывает begin на lvalue (rvalue-ness не используется).

Обойти это невозможно, вы не можете сделать так, чтобы в диапазоне for можно было повторять только rvalue. Для справки, std::ranges::istream_view делает то же самое, и единственное, что он делает для безопасности, — делает свой итератор доступным только для перемещения, поэтому того, что у вас уже есть, должно быть достаточно.


Что касается вашего второго вопроса, если вы вернете временное значение из iterator && begin() &&, оно будет уничтожено до того, как функция вернется, и вы получите висячую ссылку. Ваша текущая функция end страдает от той же проблемы. Просто верните значение iterator begin() &&. Переход от временного следует исключить.

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