Использование reverse_iterator вместо const_reverse_iterator и получение неприятных предупреждений и ошибок компилятора - PullRequest
0 голосов
/ 27 сентября 2018

Я сейчас нахожусь в процессе изучения C ++ и столкнулся с проблемой при использовании

std::string::reverse_iterator 

для обращения строки.Я получаю неприятные ошибки компилятора при попытке запустить функцию ниже.Однако, когда я переключаюсь на использование

std::string::const_reverse_iterator

, код компилируется и запускается успешно.Почему это так, особенно когда в документации по языку говорится, что обратные итераторы могут быть объявлены и использованы?Что делать, если мне нужно сказать, удалить элементы из строки, проходя по ней в обратном порядке, и хотите использовать обратный итератор?A

const_reverse_iterator

наверняка не хватит в этом случае.Любая помощь приветствуется.:)

std::string reverse(const std::string &str)
{
    std::string::reverse_iterator r_iter;
    std::string result;

    for (r_iter = str.rbegin(); r_iter < str.rend(); r_iter++) {
            result += (*r_iter);
    }

    return result;
}

Некоторые из этих ошибок:

/usr/include/c++/7/bits/stl_iterator.h: In instantiation of ‘std::reverse_iterator<_Iterator>::reverse_iterator(const std::reverse_iterator<_Iter>&) [with _Iter = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; _Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >]’:
chap6.cpp:40:34:   required from here
/usr/include/c++/7/bits/stl_iterator.h:148:22: error: no matching function for call to ‘__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >::__normal_iterator(std::reverse_iterator<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > >::iterator_type)’
  : current(__x.base()) { }

и

/usr/include/c++/7/bits/stl_iterator.h:775:26: note:   candidate expects 0 arguments, 1 provided
/usr/include/c++/7/bits/stl_iterator.h:760:11: note: candidate: constexpr __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >::__normal_iterator(const __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&)
     class __normal_iterator
           ^~~~~~~~~~~~~~~~~
/usr/include/c++/7/bits/stl_iterator.h:760:11: note:   no known conversion for argument 1 from ‘std::reverse_iterator<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > >::iterator_type {aka __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >}’ to ‘const __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&’

Ответы [ 4 ]

0 голосов
/ 27 сентября 2018

Обратите внимание, что str вашей функции является аргументом типа const.Функция rbegin () должна возвращать итератор константного типа.Это разумно.

Объявление rbegin () выглядит следующим образом:

      reverse_iterator rbegin();
const_reverse_iterator rbegin() const;

Таким образом, вы можете удалить ключевое слово const из списка параметров функции, чтобы запустить его, или изменитьstr через reverse_iterator.

0 голосов
/ 27 сентября 2018

Вся проблема правильности констант user463035818 указал в сторону.Вы демонстрируете некоторые недиоматические (для C ++) привычки написания кода.

Во-первых, не определяйте r_iter, прежде чем вам это понадобится, скорее ограничьте его рамками цикла.Кроме того, это тот случай, когда вам действительно не нужен точный тип итератора.Вы просто хотите правильный тип итератора от функции-члена.

Так что просто используйте auto для типа итератора.

std::string reverse(const std::string &str)
{
    std::string result;

    for (auto r_iter = str.rbegin(); r_iter < str.rend(); r_iter++) {
            result += (*r_iter);
    }

    return result;
}

Теперь ваш код по умолчанию верен.И если вы do попытаетесь изменить входную строку по ошибке, надеюсь, ошибка будет гораздо понятнее, чем при случайном выборе неверного типа итератора.

0 голосов
/ 27 сентября 2018

У вас есть const std::string, что означает, что вы можете делать только const вещи с ним.Существует две перегрузки: std::string::rbegin():

reverse_iterator rbegin();
const_reverse_iterator rbegin() const;

Первое недоступно для вас, но второе - нет.

std::string reverse(const std::string &str)
{
    std::string result;

    for (auto r_iter = str.rbegin(); r_iter != str.rend(); r_iter++) {
            result += *r_iter;
    }

    return result;
}

Обратите внимание, что вы недаже не нужен цикл, потому что вы можете создать std::string из пары итераторов, см. overload (6)

std::string reverse(const std::string &str)
{
    return /* std::string */ { str.rbegin(), str.rend() };
}
0 голосов
/ 27 сентября 2018

str передается как const&, поэтому вы не можете удалить из него элементы и также не можете получить неконстантный итератор, если вы хотите изменить его, вам нужно удалить const:

std::string reverse(std::string &str)
                //  ^---------------------- no const if you want to modify it !!!
{
    std::string::reverse_iterator r_iter;
    std::string result;

    for (r_iter = str.rbegin(); r_iter < str.rend(); r_iter++) {
            result += (*r_iter);
    }

    return result;
}

Это вопрос правильности.Вы не можете получить неконстантный итератор для константной строки, потому что это позволит вам изменять элементы строки, которая является константой в точности.

Также обратите внимание, что есть std::reverse, который вы можете использовать дляперевернуть строку на место .Если вы все еще хотите сохранить оригинал, ваш метод может выглядеть следующим образом:

std::string reverse(std::string str)
                //  ^ pass by value because we need a copy anyhow 
{
    std::reverse(str.begin(),str.end());    
    return str;
}

Однако вместо того, чтобы сначала копировать, а затем выполнить реверс, это можно сделать за один шаг, как показано в ответе Caleths.

...