c++c++20string-viewstd-span

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


Solution

  • 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, std::size (raw_strings)> sa;
    std::ranges::copy (raw_strings, sa.begin());
    std::span s { sa };