Reputation: 338
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
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
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