【问题标题】:Why can't I create a std::string_view from std::string iterators?为什么我不能从 std::string 迭代器创建 std::string_view ?
【发布时间】:2021-10-27 10:20:32
【问题描述】:

可以从std::string 轻松创建std::string_view。但是如果我想使用std::string 的迭代器创建一个std::string 范围的字符串视图就不行了。

这是我尝试过的代码:https://gcc.godbolt.org/z/xrodd8PMq

#include <iostream>
#include <string>
#include <string_view>
#include <iterator>

int main()
{
    std::string str{"My String"};
    std::string_view strView{str};  // works
    //std::string_view strSubView{str.begin(), str.begin() + 2}; // error
}

当然,也许我们可以从str 中提取出子字符串,然后使用strSubView 制作字符串视图,但需要创建额外的字符串。

我发现std::basic_string_view的第五个构造函数取了迭代器的范围。

template<class It, class End>
constexpr basic_string_view(It first, End last);

但它只是 std::string 的迭代器还是 std::basic_string_view 本身?如果不是 std::string 的迭代,为什么我们不应该有一个,毕竟字符串视图:

描述一个可以引用一个常量连续序列的对象 类似字符的对象!

取char的连续序列的范围,不应该算吗?

【问题讨论】:

  • 该构造函数是在 C++20 中添加的。如果您使用 C++17 编译器进行编译,则它不存在。 It works if you target C++20
  • “我们可以从 str... strSubView = strView.substr( 0, 2 );。这将与您正在尝试的内容相媲美。
  • @Caleth 哦,是的,这只是在我的眼皮底下,但我没有注意到 cppreference 中的语言标签。这意味着在 C++17 中没有办法做到这一点??

标签: c++ c++17 stdstring string-view


【解决方案1】:

That constructor is added in C++20。如果您使用 C++17 编译器进行编译,则它不存在。

你可以写一个做同样事情的函数

std::string_view range_to_view(std::string::iterator first, std::string::iterator last) {
    return first != last ? { first.operator->(), last - first } : { nullptr, 0 };
}

【讨论】:

  • 我希望 std::string_view 将在我调用range_to_view 的地方构建?
  • @Const 它是一个未实现的临时对象,它在调用站点就地构建
  • 如果first 指向结束,operator-&gt; 将失败
  • @DmytroOvdiienko 不,你会在末尾得到一个指针
  • 在 MSVC STL 的 operator-&gt;() 的正文中,如果您尝试在 end 指针上调用此函数,则会导致应用程序崩溃。而g++编译失败godbolt.org/z/fGxfnoxhd
【解决方案2】:

为什么我不能从 std::string 迭代器创建 std::string_view?

您可以,但仅从 C++20 开始。

但它只是 std::string 的迭代器还是 std::basic_string_view 本身?

它是适当值类型的任何连续迭代器。字符串和字符串视图迭代器都被接受。文档中列出了确切的限制条件。

这意味着在 C++17 中没有办法做到这一点??

没有办法使用不存在的构造函数,但是有几种方法可以获得你想要的字符串视图。这是一个:

std::string_view strSubView = strView.substr(0, 2);

或者没有中间变量:

std::string_view strSubView = std::string_view{str}.substr(0, 2);

或者如果你只有那些迭代器并且无法访问字符串:

std::string_view strSubView {&*first, last - first};

【讨论】:

  • 感谢您的解释,在我能够使用 C++20 之前,我更喜欢辅助函数。
  • 如果first 指向end&amp;*first 可能会崩溃
  • &amp;*first 与 Caleth 的回答中的 first.operator-&gt;() 相同,对吧?
  • @Peter-ReinstateMonica 实际上是的。
【解决方案3】:

因为取消引用迭代器是不安全的(即在指向 end 的迭代器上调用 operator*operator-&gt; 会使您的应用程序崩溃),我看到的 C++17 中唯一的方法是调用 @987654323 @ 并且只使用迭代器来计算大小和索引。

constexpr std::string_view make_string_view(std::string_view str, 
                                            std::string_view::iterator first, 
                                            std::string_view::iterator last) noexcept
{
    return str.substr(first - str.begin(), last - first);
}

对于std:string,使用std::string::data()作为初始指针。

std::string_view make_string_view(std::string const& str, 
                                  std::string::const_iterator first, 
                                  std::string::const_iterator last) noexcept
{
    return std::string_view(str.data() + (first - str.begin()), last - first);
}

【讨论】:

    猜你喜欢
    • 2020-04-12
    • 2017-11-22
    • 2010-10-06
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    相关资源
    最近更新 更多