I'm trying to use modern string-handling approaches (like std::string_view
or GSL's string_span
) to interact with a C API (DBus) that takes strings as null-terminated const char*
s, e.g.
DBusMessage* dbus_message_new_method_call(
const char* destination,
const char* path,
const char* iface,
const char* method
)
string_view
and string_span
don't guarantee that their contents are null-terminated - since spans are (char* start, ptrdiff_t length)
pairs, that's largely the point. But GSL also provides a zstring_view
, which is guaranteed to be null-terminated. The comments around zstring_span
suggest that it's designed exactly for working with legacy and C APIs, but I ran into several sticking points as soon as I started using it:
Representing a string literal as a
string_span
is trivial:cstring_span<> bar = "easy peasy";
but representing one as a
zstring_span
requires you to wrap the literal in a helper function:czstring_span<> foo = ensure_z("odd");
This makes declarations noisier, and it also seems odd that a literal (which is guaranteed to be null-terminated) isn't implicitly convertible to a
zstring_span
.ensure_z()
also isn'tconstexpr
, unlike constructors and conversions forstring_span
.There's a similar oddity with
std::string
, which is implicitly convertible tostring_span
, but notzstring_span
, even thoughstd::string::data()
has been guaranteed to return a null-terminated sequence since C++11. Again, you have to callensure_z()
:zstring_span<> to_zspan(std::string& s) { return ensure_z(s); }
There seems to be some const-correctness issues. The above works, but
czstring_span<> to_czspan(const std::string& s) { return ensure_z(s); }
fails to compile, with errors about being unable to convert from
span<char, ...>
tospan<const char, ...>
This is a smaller point than the others, but the member function that returns a
char*
(which you would feed to a C API like DBus) is calledassume_z()
. What's being assumed when the constructor ofzstring_span
expects a null-terminated range?
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?