考虑以下代码:
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);
此代码编译并运行良好,因为
std::span
可以从 std::vector
构造。
现在,我正在尝试将其包装成一个单独的函数:
void do_wrap (const std::vector<float>& foo) {
std::span<float> bar (foo);
do_smth (&bar);
}
问题就出现了:
错误:没有匹配的函数可用于调用 'std::span
::span(const std::vector &)'`
更准确地说,
const std::vector<float>&
不满足约束条件。
这有什么原因吗?我现在怀疑
const
限定符。
构建为
bar (foo.data(), foo.size())
会报告类似的错误。
使用 g++ 14.2.0、MinGW64 编译。
您无法修改
const std::vector<float>&
元素,但可以修改 std::span<float>
元素,因此两者不兼容。
您应该使用
std::span<const float>
来代替。
旁注:
std::span
是一种轻量级传值类型(它是一个指针和一个大小),您可以将其按值传递给函数。
void do_smth(std::span<const float> arg);
void do_wrap (const std::vector<float>& foo)
{
do_smth(bar); // implicitly constructs std::span<const float>
}
如果您正在与 C API 交互,那么最好更新 C API 以期望
const float*
做出不显式修改数据的承诺,但如果您无法修改它,那么您可以使用 const_cast
在 C API 边界的 do_smth
内部,丢弃 const 的风险由您自行承担。如果该函数实际上修改了数据,那么您就有未定义的行为。
您可以将
do_wrap
写为 span
作为参数,并传递 vector
作为参数。如果您需要重复进行转换,您可能需要使用这个版本的do_wrap
,它也说明了该技术。
注意:另一个答案是在我写我的文章时发布的。如果 C 函数需要
const
,您可以返回 const span
。我修改了代码来演示这一点。
#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;
}