In a previous post I have introduced the span<T> type from the Guidelines Support Library. This is a non-owning range of contiguous memory recommended to be used instead of pointers (and size counter) or standard containers (such as vector or array). span<T> can be used with strings, but the Guidelines Support Library provides a different span implementation for various types of strings. These string span types are available in the string_span.h header.
String span types
There are several string span types defined in the string_span.h header:
- basic_string_span: the actual implementation for a string span on which several type aliases are available:
- string_span: a string span of char
- cstring_span: a string span of const char
- wstring_span: a string span of wchar_t
- cwstring_span: a string span of const wchar_t
1234567891011template<std::ptrdiff_t Extent = dynamic_range>using string_span = basic_string_span<char, Extent>;template<std::ptrdiff_t Extent = dynamic_range>using cstring_span = basic_string_span<const char, Extent>;template<std::ptrdiff_t Extent = dynamic_range>using wstring_span = basic_string_span<wchar_t, Extent>;template<std::ptrdiff_t Extent = dynamic_range>using cwstring_span = basic_string_span<const wchar_t, Extent>; - basic_zstring_span: a null terminated string span used for converting null terminated spans to legacy strings; it has several type aliases available:
- zstring_span: a null terminated string span of char
- czstring_span: a null terminated string span of const char
- wzstring_span: a null terminated string span of wchar_t
- cwzstring_span: a null terminated string span of const wchar_t
1234567891011template <std::ptrdiff_t Max = dynamic_range>using zstring_span = basic_zstring_span<char, Max>;template <std::ptrdiff_t Max = dynamic_range>using wzstring_span = basic_zstring_span<wchar_t, Max>;template <std::ptrdiff_t Max = dynamic_range>using czstring_span = basic_zstring_span<const char, Max>;template <std::ptrdiff_t Max = dynamic_range>using cwzstring_span = basic_zstring_span<const wchar_t, Max>;
These look like a lot of classes with similar names, but the names are self explanatory (terminology is c=const, w=wide, z=null-terminated):
- string: a string of char
- cstring: a string of const char
- wstring: a string of wchar_t
- cwstring: a string of const wchar_t
- zstring: a (zero) null-terminated string of char
- czstring: a null-terminated string of const char
- wzstring: a null-terminated string of wchar_t
- cwzstring: a null-terminated string of const wchar_t
Creating a string_span
A string_span can be created in many ways, including:
(Note that in all following examples the string span is the range { L'H',L'e',L'l',L'l',L'o',L' ',L'w',L'o',L'r',L'l',L'd' } of either char or wchar_t.)
- from a literal string
123gsl::cstring_span<> s1 = gsl::ensure_z("Hello world");gsl::cwstring_span<> s2 = gsl::ensure_z(L"Hello world"); - from a pointer
12345const char* t1 = "Hello world";gsl::cstring_span<> s1 = gsl::ensure_z(t1);const wchar_t* t2 = L"Hello world";gsl::cwstring_span<> s2 = gsl::ensure_z(t2);
- from a standard string
12345std::string str1 = "Hello world";gsl::cstring_span<> s1 = str1;std::wstring wstr1 = L"Hello world";gsl::cwstring_span<> s2 = wstr1;
- from an array
12345char a1[] = "Hello world";gsl::cstring_span<> s1 = gsl::ensure_z(a1);wchar_t a2[] = L"Hello world";gsl::cwstring_span<> s2 = gsl::ensure_z(a2);
- from a vector
12345std::vector<char> vec1 = { 'H','e','l','l','o',' ','w','o','r','l','d' };gsl::string_span<> s1 = vec1;std::vector<wchar_t> vec2 = { L'H',L'e',L'l',L'l',L'o',L' ',L'w',L'o',L'r',L'l',L'd' };gsl::wstring_span<> s2 = vec2;
Converting to string
To convert a string span into a string you can use the to_string() function.
1 2 3 4 5 6 7 |
char a1[] = "Hello world"; gsl::cstring_span<> s1 = gsl::ensure_z(a1); std::string str1 = gsl::to_string(s1); // str1 = "Hello world" wchar_t a2[] = L"Hello world"; gsl::cwstring_span<> s2 = gsl::ensure_z(a2); std::wstring str2 = gsl::to_string(s2); // str2 = L"Hello world" |
Size of a string_span
Unlike span<T>, a string_span<T> only have one dimension, so the rank() method does not make make sense and is not available. However, a string span has several methods for the size of the span:
- size() and length(): return the number of elements of the span
- size_bytes() and length_bytes(): return the number of bytes of the span
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
std::string str1 = "Hello world"; gsl::cstring_span<> s1 = str1; std::cout << "length=" << s1.length() << std::endl; // length=11 std::cout << "size=" << s1.size() << std::endl; // size=11 std::cout << "length bytes=" << s1.length_bytes() << std::endl; // length bytes=11 std::cout << "size bytes=" << s1.size_bytes() << std::endl; // size bytes=11 std::wstring str2 = L"Hello world"; gsl::cwstring_span<> s2 = str2; std::cout << "length=" << s2.length() << std::endl; // length=11 std::cout << "size=" << s2.size() << std::endl; // size=11 std::cout << "length bytes=" << s2.length_bytes() << std::endl; // length bytes=22 std::cout << "size bytes=" << s2.size_bytes() << std::endl; // size bytes=22 |
Subspans
It is possible to create subspans from a string_span. There are several functions that do that:
- first(): returns the sub-span with the first N elements from the original string_span
- last(): returns the sub-span with the last N elements from the original string_span
- subspan(): returns the sub-span within the specified range (first and last positions) of the original string_span.
1 2 3 4 5 |
std::string str1 = "Hello world"; gsl::cstring_span<> s1 = str1; // s1 = { 'H','e','l','l','o',' ','w','o','r','l','d' } gsl::cstring_span<> l = s1.first(5); // l = { 'H','e','l','l','o' } gsl::cstring_span<> r = s1.last(5); // r = { 'w','o','r','l','d' } gsl::cstring_span<> m = s1.subspan(3, 5); // m = { 'l','o',' ','w','o' } |
Comparisons
You can use the comparison operators (==, !=, <, <=, >, >=) with two string spans. Just like in the case of span<T>, equality is checked with std::equal (two ranges are equal if every element in the first range is equal to the element corresponding to the same position in the second range) and less/greater is checked with std::lexicographical_compare() (one range is less than another if the first mismatch element in the first range is less than the element on the same position in the second range).
1 2 3 4 5 6 7 8 9 10 |
std::string str1 = "Hello world"; gsl::cstring_span<> s1 = str1; std::string str2 = "Hello world!"; gsl::cstring_span<> s2 = str2; std::cout << (s1 == s2) << std::endl; // prints 0 std::cout << (s1 != s2) << std::endl; // prints 1 std::cout << (s1 < s2) << std::endl; // prints 1 std::cout << (s1 > s2) << std::endl; // prints 0 |
Element access
It is possible to access the content of a string_span either with iterators or indexes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
std::string str = "Hello world"; gsl::cstring_span<> s = str; // prints Hello world for (auto const & e : s) std::cout << e; std::cout << std::endl; // prints dlrow olleH for (auto it = s.rbegin(); it != s.rend(); ++it) std::cout << *it; std::cout << std::endl; // prints Hello world for (auto it = std::begin(s); it != std::end(s); ++it) std::cout << *it; std::cout << std::endl; // prints Hello world for (ptrdiff_t i = 0; i < s.size(); ++i) std::cout << s[i]; std::cout << std::endl; //s[5] = '-'; // Error C3892 's': you cannot assign to a variable that is const |
1 2 3 4 5 6 7 8 9 |
std::string str = "Hello world"; gsl::string_span<> s = str; s[5] = '-'; // prints Hello-world for (ptrdiff_t i = 0; i < s.size(); ++i) std::cout << s[i]; std::cout << std::endl; |
In your last code snippet, why do you use ptrdiff_t on line 7?
> span can be used with strings, but the Guidelines Support Library provides a different span implementation for various types of strings. These string span types are available in the string_span.h header.
So span can only be used for strings, but string_span can be used for other types? A little confusing… could you perhaps clarify the differences between gsl::span, gsl::string_span and also std::span (c++17) ? When would you use which one and why? That would be really helpful! Thanks!
What is confusing? I don’t find anything confusing. “span<T> can be used with strings”. I don’t understand why that became “span can only be used for strings” for you. There is a span type that can be used with various types of ranges including strings or char arrays, but there is also a string_span, that is a range of strings (and cannot be used with other types like ints).
So afaict the unique properties are:
gsl::span rw, multi-demensional, arbitrary alphabets
gsl::string_span rw, one-dimensional, character alphabets, has a to_string() and a length() member
And
std::span / array_view / string_view would be like string_span except that it is read-only
[http://stackoverflow.com/questions/34832090/whats-the-difference-between-span-and-array-view-in-the-gsl-library]
Is that correct so far?
Thank you for your reply!