Search code examples
c++c++20stdvectorstd-span

Cannot construct `std::span<T>` from `const std::vector<T>&`


Consider the following code:

std::vector<float> foo = some_generator_function();
std::span<float> bar {foo};
/* Wrapper for C API that uses bar->data() and bar->size_bytes()
 * if bar != nullptr, guaranteed not to change any data in bar.
 * In some cases bar is constructed from a const C array.
 */
do_smth (&bar);

This code compiles and works fine, as std::span can be constructed from a std::vector.

Now, I'm trying to wrap it into a separate function:

void do_wrap (const std::vector<float>& foo) {
    std::span<float> bar (foo);
    do_smth (&bar);
}

And the problem arises:

error: no matching function for call to 'std::span<float>::span(const std::vector<float>&)'`

More precisely, const std::vector<float>& does not satisfy constraints.

Is there any reason for this? I'm suspecting the const qualifier for now.

Constructing as bar (foo.data(), foo.size()) reports a similar error.

Compiling with g++ 14.2.0, MinGW64.


Solution

  • You cannot modify const std::vector<float>& elements, but you can modify std::span<float> elements, so the two are not compatible.

    you should be using a std::span<const float> instead.


    side note: std::span is a lightweight pass-by-value type (it is a pointer and a size), you can pass it to functions by-value.

    void do_smth(std::span<const float> arg);
    
    void do_wrap (const std::vector<float>& foo) 
    {
      do_smth(foo); // implicitly constructs std::span<const float>
    }
    

    If you are interacting with a C API then it is better to update the C API to expect a const float* to make its promise of not modifying the data explicit, but if you can't modify it then you can use const_cast inside do_smth at the C API boundary to cast away the const at your own risk. if the function actually modified the data then you have undefined behavior.