使用 string_view 构造 istringstream 无法编译

问题描述 投票:0回答:4

我无法向

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()

c++ c++17
4个回答
8
投票

这个问题对我来说很奇怪,因为这里应该发生 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
) 很便宜,因此是隐式的。


6
投票

除了其他答案之外,如果使用 stringview 的目的是避免复制 char 缓冲区,那么将其复制到 istringstream 的 std::string 中并不令人满意。

在这种情况下,您可以使用 Boost 的

iostream
作为 stringstream 的直接替代品 - 这可以避免复制缓冲区。

#include <boost/iostreams/stream.hpp>

boost::iostreams::stream<boost::iostreams::array_source> stream(buffer, size);

1
投票

这里的问题是,采用

std::string
std::string_view
构造函数被标记为
explicit
。 这意味着您不能在隐式转换序列中使用它。

您需要添加强制转换来显式转换它,或者使用

std::string
/
const char[]
来代替。


0
投票

从 C++23 开始:使用
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 版本开始就已经支持了。)

© www.soinside.com 2019 - 2024. All rights reserved.