Стереть внутри std :: string с помощью std :: string_view - PullRequest
0 голосов
/ 06 мая 2020

Мне нужно найти и затем стереть часть строки (подстроку). string_view кажется хорошей идеей, но я не могу заставить ее работать с string::erase:

// guaranteed to return a view into `str`
auto gimme_gimme_gimme(const std::string& str) -> std::string_view;

auto after_midnight(std::string& str)
{
    auto man = gimme_gimme_gimme(str);

    str.erase(man); // way to hopeful, not a chance though
    str.erase(man.begin(), man.end()); // nope
    str.erase(std::distance(str.begin(), man.begin()), man.size()); // nope
    str.erase(std::distance(str.data(), man.data()), man.size()); // nope again

    // for real???
}

Я слишком много думаю об этом? Учитывая std::string_view в std::string, как стереть эту часть строки? Или я неправильно использую string_view?

Ответы [ 2 ]

1 голос
/ 06 мая 2020

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

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

Я не думаю, что строковое представление является идеальным способом представления поддиапазона в этом случае. Вместо этого я бы предложил использовать относительный поддиапазон на основе индексов. Например:

struct sub_range {
    size_t begin;
    size_t count;
    constexpr size_t past_end() noexcept {
        return begin + count;
    }
};

Вопрос вкуса, использовать ли end (т.е. past_end) или count для второго члена, а другой предоставлять как функцию. Тем не менее, не должно быть путаницы, потому что у участника будет имя. Использование count несколько более стандартно с индексами.

Другой выбор - использовать ли индексы со знаком или без знака. Индексы со знаком могут использоваться для представления обратных диапазонов. Однако интерфейс std::string не поддерживает такие диапазоны.

Пример использования:

auto gimme_gimme_gimme(const std::string& str) -> sub_range;

auto after_midnight(std::string& str)
{
    auto man = gimme_gimme_gimme(str);
    str.erase(man.begin, man.distance);
}
1 голос
/ 06 мая 2020

Неужели я над этим слишком много думаю?

Вы не думаете об этом, если я не упускаю что-то очевидное. Для компиляции кода вам понадобится следующее:

auto gimme_gimme_gimme(const std::string& str) -> std::string_view;

auto after_midnight(std::string& str)
{
    auto man = gimme_gimme_gimme(str);

    str.erase(std::distance(std::as_const(str).data(), man.data()), man.size()); // urrr... growling in pain
}

Но подождите !! Есть еще кое-что! Заметьте, я сказал "сделать его компилированным". Код подвержен ошибкам !! Потому что ...

std::string::data не может быть nullptr, но пустой string_view может быть представлен как (действительный указатель внутри строки + size 0) или как (nullptr + size 0) . Проблема возникает, если string_view::data равно nulltpr из-за используемого std::distance.

Поэтому вам нужно убедиться, что string_view всегда указывает внутри строки, даже если представление пусто. Или сделайте дополнительную проверку на стираемой стороне.

...