[英]Use of std::span<std::span<uint8_t>>
我经常使用 C++20 的这个新功能: std::span<T>
。 这对于编写通常需要指针和大小的函数很有用。
#include <array>
#include <span>
#include <vector>
std::vector<uint8_t> v1 {1,2,3,4,5};
std::array<uint8_t, 4> v2 {1,2,3,4};
uint8_t v3[3] = {1,2,3};
void f(std::span<uint8_t> arr){
...
}
/// call f with v1 or v2 or v3
f(v1);
f(v2);
f(v3);
现在,我想要一个 function 作为参数跨度跨度。
std::vector<std::array<uint8_t,10>> v1;
v1.push_back({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
v1.push_back({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
v1.push_back({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
void f(std::span<std::span<uint8_t, 10>> arr){
...
}
f(v1);
不幸的是,这根本没有编译。 这将是一种使用二维数组的方法。
编译错误:
<source>:21:1: error: no matching function for call to 'f'
f(v1);
^
<source>:8:6: note: candidate function not viable: no known conversion from 'std::vector<std::array<uint8_t, 10>>' (aka 'vector<array<unsigned char, 10>>') to 'std::span<std::span<uint8_t, 10>>' (aka 'span<span<unsigned char, 10>>') for 1st argument
void f(std::span<std::span<uint8_t, 10>> arr){
^
1 error generated.
ASM generation compiler returned: 1
<source>:21:1: error: no matching function for call to 'f'
f(v1);
^
<source>:8:6: note: candidate function not viable: no known conversion from 'std::vector<std::array<uint8_t, 10>>' (aka 'vector<array<unsigned char, 10>>') to 'std::span<std::span<uint8_t, 10>>' (aka 'span<span<unsigned char, 10>>') for 1st argument
void f(std::span<std::span<uint8_t, 10>> arr){
^
1 error generated.
Execution build compiler returned: 1
您对如何在不使用原始指针的情况下使其工作有任何想法吗?
这不起作用,因为向量不包含跨度。 这个错误有点类似于试图将int[x][y]
传递给 function 接受int**
。
您应该:
std::span<std::array<uint8_t,10>>
访问向量void f2(std::span<std::array<uint8_t,10>> arr)
auto to_span = [](auto& arr) -> std::span<uint8_t, 10> { return {arr}; }; auto span_range = std::ranges::transform_view(v1, to_span); std::vector v2(std::begin(span_range), std::end(span_range)); f(v2);
它并不总是数组的向量
如果您有时想使用一种类型的参数而其他时间使用另一种类型的参数,那么也许您应该定义一个 function 模板:
template<class Range> void f3(Range& range)
但我正在寻找另一种方式,因为它有一定的成本 O(N)。
创建向量时,您已经支付了O(N) * O(M)
的成本。 顶部的O(N)
不太可能很重要。
跨度要求你跨越的东西实际上在一个连续的缓冲区中。
那里没有actusl span 对象的连续缓冲区。 有一个可转换为 span 对象的连续缓冲区。
在这种特定情况下,子对象是统一的且大小不变,但它们的数量是可变的。
std span 的优点之一是转换开销几乎为零; 要制作一个实际的跨度跨度,必须为每个子跨度完成几乎零(但不是零)的工作。
如果你觉得这没问题,那么编写一个自动矢量构建器是合理的:
templafr<class T>
struct autoconverting_vector:std::vector<T> {
using base=std::vector<T>::vector;
using base::base;
template<class Range> requires( Range's iterators elements are convertible to T )
autoconverting_vector( Range&& range ): base(begin(range), end(range)) {}
};
然后取一个autoconverting_vector<span<uint8_t>>
另一种选择是编写二维跨度类型; 这仅在第二维是 std 数组或类似数组时才有效,因为子元素布局是固定的并且只是数学。
您可以为此使用 n 维数组视图类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.