c++ - 将 gsl::zstring_view 与 C API 结合使用

标签 c++ string-view cpp-core-guidelines guideline-support-library string-span

我正在尝试使用现代字符串处理方法(如 std::string_view GSL's string_span )与 C API (DBus) 进行交互,该 C API (DBus) 将字符串视为空终止 const char* s,例如

DBusMessage* dbus_message_new_method_call(
    const char* destination,
    const char* path,
    const char* iface,
    const char* method 
    )

string_viewstring_span不保证它们的内容以空终止 - 因为跨度是 (char* start, ptrdiff_t length)成双成对,这就是重点。但GSL还提供了zstring_view保证以空终止。 comments左右zstring_span建议它是专门为处理旧版 API 和 C API 而设计的,但我一开始使用它就遇到了几个症结点:

  1. 将字符串文字表示为 string_span是微不足道的:

    cstring_span<> bar = "easy peasy";
    

    但将一个表示为 zstring_span要求您将文字包装在辅助函数中:

    czstring_span<> foo = ensure_z("odd");
    

    这使得声明变得更加嘈杂,而且文字(保证以 null 结尾)不能隐式转换为 zstring_span 似乎也很奇怪。 。 ensure_z()也不是constexpr ,与 string_span 的构造函数和转换不同.

  2. std::string 也有类似的奇怪现象。 ,可隐式转换为 string_span ,但不是zstring_span ,尽管 std::string::data()自 C++11 起,已保证返回空终止序列。再次强调,您必须调用ensure_z() :

    zstring_span<> to_zspan(std::string& s) { return ensure_z(s); }
    
  3. 似乎存在一些常量正确性问题。上面的方法有效,但是

    czstring_span<> to_czspan(const std::string& s) { return ensure_z(s); }
    

    编译失败,出现无法从 span<char, ...> 转换的错误至span<const char, ...>

  4. 这是一个比其他点更小的点,但是返回 char* 的成员函数(您可以将其提供给 DBus 等 C API)称为 assume_z() 。当 zstring_span 的构造函数时,假设是什么? expects a null-terminated range

如果zstring_span被设计为“将零终止的跨度转换为遗留字符串”,为什么它在这里的使用看起来如此麻烦?我是否滥用它?有什么我忽略的事情吗?

最佳答案

  1. it also seems odd that a literal (which is guaranteed to be null-terminated) isn't implicitly convertible to a zstring_span

字符串文字的类型为 const char[...] 。类型中没有任何信息表明此const char array 是一个以 null 结尾的字符串。这是具有相同类型的其他一些代码,但没有空终止,其中 ensure_z很快就会失败。

const char foo_arr[4]{ 'o', 'd', 'd', '-' };
ensure_z(foo_arr);

两者"foo"foo_arr类型为const char[4] ,但只有字符串文字以 null 结尾,而 foo_arr不是。

请注意您的 ensure_z 的组合和czstring_span<>可以编译,但是不起作用。 ensure_z仅返回不带终止空字节的字符串。当您将其传递给czstring_span<>时构造函数,那么构造函数将无法搜索空字节(被 ensure_z 截断)。

您需要将字符串文字转换为跨度并将其传递给构造函数:

czstring_span<> foo = ensure_span("odd");
  1. There's a similar oddity with std::string, which is implicitly convertible to string_span, but not zstring_span

好点。有一个 string_span 的构造函数这需要 std::string ,但是对于 zstring_span只有一个采用内部实现类型的构造函数,a span<char> 。对于 span有一个构造函数采用一个具有 .data() 的“容器”和.size() - 其中std::string实现。更糟糕的是:以下代码可以编译但无法运行:

zstring_span<> to_zspan(std::string& s) { return zstring_span<>{s}; }

您应该考虑在 GSL 存储库中提交问题以使类保持一致。我不确定隐式转换是否是一个好主意,所以我更喜欢 zstring_span 中的完成方式怎么样string_span做到了。

  1. There seems to be some const-correctness issues.

这也是我的第一个想法 czstring_span<> to_czspan(const std::string& s) { return czstring_span<>{s}; }编译但不起作用。另一个解决方案是一个新函数 ensure_cz返回 span<const char, ...> 。您应该考虑提出问题。

  1. assume_z()

empty()的存在以及 as_string_span() 中的代码表明该类旨在能够处理空字符串范围。在这种情况下as_string_span总是返回字符串而不终止空字节,ensure_z将返回带有终止空字节的字符串,如果为空则失败,并且 assume_z会假设 !empty()并返回以空字节结尾的字符串。

但是唯一的构造函数采用非空字符范围,因此 empty()永远不可能true 。我刚刚创建了一个 PR来解决这些不一致的问题。如果您认为应该进行更多更改,请考虑提出问题。

If zstring_span is designed "to convert zero-terminated spans to legacy strings", why does its use here seem so cumbersome? Am I misusing it? Is there something I'm overlooking?

在纯 C++ 代码中,我更喜欢 std::string_view , zstring_span仅适用于 C 互操作,这限制了它的使用。当然,您必须了解指南和指南支持库。鉴于我打赌zstring_span很少被使用,并且您是极少数深入研究它的人之一。

关于c++ - 将 gsl::zstring_view 与 C API 结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56874532/

相关文章:

C++、OpenGL - 渲染大量的……茶壶

c++ - string_view 和 basic_string<char> 有什么联系,为什么 string_view 示例代码不起作用?

c++ - 核心 cpp 指南中 f(T*, int) 接口(interface)与 f(span<T>) 接口(interface)的含义

c++ - gsl::suppress 整个包含语句

C++ 比较两个结构以显示有什么区别

C++编译器模板错误信息-解码错误信息的工具

.net - 创建 C++ 控件并在 C# 中使用它可以获得性能吗?

c++ - 传递临时 std::string 时的 string_view 行为

c++ - 将字符串隐式转换为 string_view

c++ - 传递 span<T> 和 std::array 作为参数有什么区别?