trexxet
trexxet

Reputation: 338

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.

Upvotes: 4

Views: 133

Answers (2)

Ahmed AEK
Ahmed AEK

Reputation: 18090

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.

Upvotes: 8

Rud48
Rud48

Reputation: 1059

You can write do_wrap with span as the parameter and pass a vector as the argument. If you need to do the conversion repeatedly, you may want to use this version of do_wrap, which also illustrates the technique.

Note: The other answer was posted while I was writing mine. If the C functions require const, you can return a const span. I modified my code to demonstrate this.

#include <span>
#include <vector>

#include <fmt/ranges.h>
using fmt::println, fmt::print;

// convert vector to span    
auto do_wrap(const std::span<float>& meow) -> const std::span<float> {
   return meow;
}

auto main() -> int {
   std::vector<float> meow{1, 2, 3};

   auto woof {do_wrap(meow)};
   println("{}", woof);
   return 0;
}

Upvotes: 0

Related Questions