我无法向
std::string_view
的构造函数提供 std::istringstream
。以下代码无法编译(使用 Clang v8 启用 C++17):
std::string_view val = "Hello";
std::istringstream ss(val, std::ios_base::in);
我得到的错误是:
prog.cc:9:24: error: no matching constructor for initialization of 'std::istringstream' (aka 'basic_istringstream<char>')
std::istringstream ss(val, std::ios_base::in);
^ ~~~~~~~~~~~~~~~~~~~~~~
/opt/wandbox/clang-6.0.0/include/c++/v1/sstream:651:14: note: candidate constructor not viable: no known conversion from 'std::string_view' (aka 'basic_string_view<char>') to 'const std::__1::basic_istringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >::string_type' (aka 'const basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >') for 1st argument
explicit basic_istringstream(const string_type& __s,
^
但是这确实:
std::string_view val = "Hello";
std::istringstream ss(val.data(), std::ios_base::in);
这个问题对我来说很奇怪,因为这里应该发生 1 次隐式转换:
std::string_view
到 std::basic_string
。构造函数正在根据错误消息获取 basic_string
。
为什么我不能在不调用
string_view
的情况下逐字使用 string_view::data()
?
这个问题对我来说很奇怪,因为这里应该发生 1 次隐式转换:
到std::string_view
。std::basic_string
A
string_view
不能隐式转换为 string
。构造函数(好吧,推导指南,但无论如何)被标记为 explicit
。
这应该有效(未经测试):
std::string_view val = "Hello";
std::istringstream ss(std::string(val), std::ios_base::in);
显式的原因是它是一个(可能)昂贵的操作;涉及内存分配和数据复制。相反的转换 (
string
--> string_view
) 很便宜,因此是隐式的。
除了其他答案之外,如果使用 stringview 的目的是避免复制 char 缓冲区,那么将其复制到 istringstream 的 std::string 中并不令人满意。
在这种情况下,您可以使用 Boost 的
iostream
作为 stringstream 的直接替代品 - 这可以避免复制缓冲区。
#include <boost/iostreams/stream.hpp>
boost::iostreams::stream<boost::iostreams::array_source> stream(buffer, size);
这里的问题是,采用
std::string
的 std::string_view
构造函数被标记为 explicit
。 这意味着您不能在隐式转换序列中使用它。
您需要添加强制转换来显式转换它,或者使用
std::string
/const char[]
来代替。
std::ispanstream
正如 @Martshall Clow 所指出的,从
std::string_view
到 std::istringstream
没有隐式转换,因为后者需要管理一个内部 std::string
,而后者又需要拥有包含字符的内存,但是 std::string_view
不拥有该内存。因此,需要一份副本。
另一方面,
std::string_view
的明确构思是为了不拥有角色,因此,std::istringstream
从根本上来说是一个糟糕的匹配。幸运的是,C++23 引入了 <spanstream>
,一种 Streambuf 实现,可与不拥有内存的固定缓冲区一起使用。我认为它是以 std::span
命名的,而不是 view,因为输出流需要可变缓冲区,而 std::span
是规范工具。但对于输入流,std::string_view
和std::span<const char>
几乎无法区分,幸运的是,std::ispanstream
包含一个通用构造函数重载,采用合适的只读范围,它可以直接采用std::string_view
。
(侧节点:不幸的是,支持仍然有些有限。从 v18 开始,libC++ (Clang) 还不支持
<spanstream>
- 另一方面,libstdc++ (GCC) 从 v12 版本开始就已经支持了。)