sim*_*ame 10 c++ string-concatenation string-view c++17
我一直std::string_view在一些旧代码中添加 s 来表示配置参数等字符串,因为它提供了只读视图,由于不需要复制,速度更快。
string_view但是,由于operator+未定义,因此无法将两个连接在一起。我看到这个问题有几个答案表明它是一个疏忽,并且有一个建议添加它。但是,这是添加 astring和 a string_view,大概如果实现的话,生成的串联将是std::string
添加两个string_view也属于同一类别吗?如果不是,为什么不string_view支持添加两个?
样本
std::string_view s1{"concate"};
std::string_view s2{"nate"};
std::string_view s3{s1 + s2};
Run Code Online (Sandbox Code Playgroud)
这是错误
error: no match for 'operator+' (operand types are 'std::string_view' {aka 'std::basic_string_view<char>'} and 'std::string_view' {aka 'std::basic_string_view<char>'})
Run Code Online (Sandbox Code Playgroud)
Cor*_*mer 13
视图与跨度类似,因为它不拥有数据,顾名思义,它只是数据的视图。要连接字符串视图,您首先需要构造 astd::string然后才能连接。
std::string s3 = std::string(s1) + std::string(s2);
Run Code Online (Sandbox Code Playgroud)
请注意,这s3将是 astd::string而不是 a std::string_view,因为它拥有此数据。
Astd::string_view是 的别名std::basic_string_view<char>,它是std::basic_string_view基于特定类型字符的模板,即char。
但它看起来是什么样子呢?
\n除了相当多的有用的成员函数,例如find、substr和其他(如果与 STL 提供的其他容器/字符串之类的东西相比,也许它是一个普通的数字), ,std::basic_string_view<_CharT>是_CharT通用的char类型,只有 2 个数据成员,
// directly from my /usr/include/c++/12.2.0/string_view\n size_t _M_len;\n const _CharT* _M_str;\nRun Code Online (Sandbox Code Playgroud)\n即一个constant 指针来_CharT指示视图从哪里开始,以及一个size_t(适当类型的数字)来指示视图从多长时间开始_M_str\ 的指针对象开始多长时间的 a (适当类型的数字)。
换句话说,字符串视图只知道它从哪里开始以及它有多长,因此它表示一系列在内存中连续的char类似实体。仅使用两个这样的成员,就无法表示由不连续的子字符串组成的字符串。
但换句话来说,如果你想创建一个std::string_view,你需要能够知道char它有多少 s 长以及从哪个位置开始。你能说出从哪里s1 + s2开始以及应该有多少个字符吗?想想看:你不能,因为s1和s2不相邻。
也许图表可以提供帮助。
\n假设这些代码行
\nstd::string s1{"hello"};\nstd::string s2{"world"};\nRun Code Online (Sandbox Code Playgroud)\ns1s2就它们的内存位置而言,它们是完全不相关的对象;它们是这样的:
&s2[0]\n |\n | &s2[1]\n | |\n&s1[0] | | &s2[2]\n | | | |\n | &s1[1] | | | &s2[3]\n | | | | | |\n | | &s1[2] | | | | &s2[4]\n | | | | | | | |\n | | | &s1[3] v v v v v\n | | | | +---+---+---+---+---+\n | | | | &s1[4] | w | o | r | l | d |\n | | | | | +---+---+---+---+---+\n v v v v v\n+---+---+---+---+---+\n| h | e | l | l | o |\n+---+---+---+---+---+\nRun Code Online (Sandbox Code Playgroud)\n我故意将它们绘制为未对齐,这意味着&s1[0], 开始的内存位置s1, 和&s2[0], 开始的内存位置s2,彼此无关。
现在,想象您创建两个像这样的字符串视图:
\nstd::string_view sv1{s1};\nstd::string_view sv2(s2.begin() + 1, s2.begin() + 4);\nRun Code Online (Sandbox Code Playgroud)\n_M_str根据两个实现定义的成员和,它们的外观如下_M_len:
&s2[0]\n |\n | &s2[1]\n | |\n &s1[0] | | &s2[2]\n | | | |\n | &s1[1] | | | &s2[3]\n | | | | | |\n | | &s1[2] | | | | &s2[4]\n | | | | | | | |\n | | | &s1[3] v v v v v\n | | | | +---+---+---+---+---+\n | | | | &s1[4] | w | o | r | l | d |\n | | | | | +---+---+---+---+---+\n v v v v v \xc2\xb7 ^ \xc2\xb7\n +---+---+---+---+---+ \xc2\xb7 | \xc2\xb7\n | h | e | l | l | o | +---+ \xc2\xb7\n +---+---+---+---+---+ | \xc2\xb7 \xc2\xb7\n \xc2\xb7 ^ \xc2\xb7 | \xc2\xb7 s2._M_len \xc2\xb7\n \xc2\xb7 | \xc2\xb7 | <----------->\n +---+ \xc2\xb7 |\n | \xc2\xb7 \xc2\xb7 +-- s2._M_str\n | \xc2\xb7 s1._M_len \xc2\xb7\n | <------------------->\n |\n +-------- s1._M_str\nRun Code Online (Sandbox Code Playgroud)\n鉴于上述情况,您能看出预期有什么问题吗?
\nstd::string_view s3{s1 + s2};\nRun Code Online (Sandbox Code Playgroud)\n作品?
\n您如何定义s3._M_str和s3._M_len(基于s1._M_str、s1._M_len、s2._M_str和s2._M_len),以便它们代表关于 的视图"helloworld"?
你不能,因为"hello"和"world"位于两个不相关的内存区域。
std::string_view不拥有任何数据,它只是一个视图。如果您想连接两个视图以获得连接视图,您可以使用boost::join()Boost 库。但结果类型将不是std::string_view.
#include <iostream>
#include <string_view>
#include <boost/range.hpp>
#include <boost/range/join.hpp>
void test()
{
std::string_view s1{"hello, "}, s2{"world"};
auto joined = boost::join(s1, s2);
// print joined string
std::copy(joined.begin(), joined.end(), std::ostream_iterator(std::cout, ""));
std::cout << std::endl;
// other method to print
for (auto c : joined) std::cout << c;
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
C++23 在标准库中加入了范围,名称为std::ranges::views::join_with_view
#include <iostream>
#include <ranges>
#include <string_view>
void test()
{
std::string_view s1{"hello, "}, s2{"world"};
auto joined = std::ranges::views::join_with_view(s1, s2);
for (auto c : joined) std::cout << c;
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13546 次 |
| 最近记录: |