Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create span of string_views from C string array

Given some function void func(std::span<std::string_view>), how does one feed this function a raw array of C-strings const char** in the most efficient manner?

As far as I understood this should be possible as without any copying as std::string_view can be constructed from a C string and std::span can be constructed from a pointer + size. However, I don't seem to be able to figure out the proper syntax.

Here's some minimal code that works when creating an std::vector<std::string_view> by iterating over each string in the string array:

#include <iostream>
#include <string>
#include <span>
#include <vector>

static void func(std::span<std::string_view> strings)
{
    // Just print the strings...
    std::cout << "strings:\n";
    for (const auto& str : strings)
        std::cout << str << "\n";
    std::cout << std::endl;
}

int main()
{
    // Raw C string array
    const char* raw_strings[3] = {
        "This is a string",
        "This is also a string",
        "And then another string"
    };
    
#if 1
    // This works
    std::vector<std::string_view> s;
    for (std::size_t i = 0; i < 3; i++)
        s.push_back( std::string_view{ raw_strings[i] } ); 
#else
    // This does not work
    std::span<std::string_view> s{ raw_strings, (std::size_t)3 };
#endif
        
    func(s);
}

Here's a coliru link with the grunt work done: https://coliru.stacked-crooked.com/a/cb8fb8ebbc962d45

like image 833
Joel Bodenmann Avatar asked Sep 23 '20 21:09

Joel Bodenmann


People also ask

How do you create a span in C++?

All of the big three C++ compilers MSVC, GCC, and Clang, support std::span. There are more ways to create a std::span. You can create a std::span from a pointer and a size. As you may expect, the from a std::vector created mySpan1 (1) and the from a pointer and a size created mySpan (2) are equal (3).

Why use span<t> instead of an array?

From this brief description, two things should be clear: Span<T> is defined in such a way that operations can be as efficient as on arrays: indexing into a span doesn’t require computation to determine the beginning from a pointer and its starting offset, as the ref field itself already encapsulates both.

What is a string in C++?

In C++, a string is usually just an array of (or a reference/points to) characters that ends with the NULL character ‘ \0 ‘. A string is a 1-dimensional array of characters and an array of strings is a 2-dimensional array of characters. 1. Using Pointers

How to use a span in c++20?

With C++20, the answer is quite easy: Use a std::span. A std::span stands for an object that can refer to a contiguous sequence of objects. A std::span, sometimes also called a view, is never an owner. This contiguous memory can be a plain array, a pointer with a size, a std::array, a std::vector, or a std::string.


1 Answers

If you think about it, to do what you are asking the compiler needs to find somewhere to store 3 std::string_views and there is no such place since std::span doesn't actually allocate any storage for the elements it references.

So, AFAICS, there's no direct way to do this.


Edit: this, I think, is the cheapest way to do it, since it involves no allocations from the free store. Take care, though, that the array doesn't go out of scope while the span is being used:

std::array <std::string_view, sizeof (raw_strings) / sizeof (raw_strings [0])> sa;
std::copy (std::begin (raw_strings), std::end (raw_strings), std::begin (sa));
std::span <std::string_view> s { sa };
like image 107
Paul Sanders Avatar answered Sep 28 '22 12:09

Paul Sanders