0

我需要找到然后删除字符串的一部分(子字符串)。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

4

2 回答 2

1

字符串视图可能确实是空的,或者它可能是容器外部的视图。您建议erase的重载以及答案中函数的实现依赖于字符串视图是相同字符串对象的前提条件。

当然,迭代器重载非常相似,并且依赖于相同的前提条件。但是这样的前置条件对于迭代器来说是常规的,但对于字符串视图来说是非常规的。

在这种情况下,我认为字符串视图不是表示子范围的理想方式。相反,我建议使用基于索引的相对子范围。例如:

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

end是使用(ie 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);
}
于 2020-05-06T16:21:05.543 回答
1

这是我想太多了吗?

你正在考虑它,除非我遗漏了一些明显的东西。要编译代码,您需要:

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总是指向字符串内部,即使视图是空的。或者在擦除方面进行额外检查。

于 2020-05-06T15:39:56.293 回答