看来std::spanC ++ 20中的定义与
template<class T>
class span
{
T* begin;
size_t count;
};
Run Code Online (Sandbox Code Playgroud)
并不是
template<class Iter>
class span
{
Iter begin;
Iter end;
};
Run Code Online (Sandbox Code Playgroud)
哪个更通用(可与std :: list,std :: map等配合使用)?
换句话说,反过来,std::span迭代器在span实例被销毁后会失效吗?
我有一个向量需要用不同的布局进行迭代。我试图std::span避免编写大量迭代器样板或引入外部库依赖项。简化示例:
#include <iostream>
#include <span>
#include <vector>
template <size_t N>
struct my_view {
std::vector<int> vec;
auto as_span() {
return std::span<int[N]>((int(*)[N])vec.data(), vec.size() / N);
}
auto begin() {
return as_span().begin();
}
auto end() {
return as_span().end();
}
};
int main() {
std::vector vec {1, 2, 3, 4, 5, 6};
my_view<2> pairs {std::move(vec)};
for (auto pair : pairs) {
std::cout << pair[0] << " " << pair[1] << std::endl;
}
my_view<3> triplets {std::move(pairs.vec)};
for (auto triplet : …Run Code Online (Sandbox Code Playgroud) 我正在使用一个 C 库,它使用各种固定大小的unsigned char数组,不带空终止符作为字符串。
我已经将它们转换为std::string使用以下函数:
auto uchar_to_stdstring(const unsigned char* input_array, int width) -> std::string {
std::string temp_string(reinterpret_cast<const char*>(input_array), width);
temp_string.erase(temp_string.find_last_not_of(' ') + 1);
return temp_string;
}
Run Code Online (Sandbox Code Playgroud)
除了使用reinterpret_cast、需要传递数组大小以及我将数组衰减为指针之外,它工作得很好。我试图通过使用 来避免所有这些问题std::span。
使用的函数std::span如下所示:
auto ucharspan_to_stdstring(const std::span<unsigned char>& input_array) -> std::string {
std::stringstream temp_ss;
for (const auto& input_arr_char : input_array) {
temp_ss << input_arr_char;
}
return temp_ss.str();
}
Run Code Online (Sandbox Code Playgroud)
该函数运行良好,使其他一切变得更简单,而无需跟踪 C 数组的大小。但是,通过一些基准测试(使用nanobench )进一步挖掘表明,新函数比经典方法慢很多倍reinterpret_cast。我的假设是基于 - 的函数for中的循环std::span是这里效率低下的。
我的问题:是否有更有效的方法将固定大小的无符号字符 C 数组从 …
我知道std::span是静态的。它只是一堆向量/数组/等的视图。元素。
我看到span的构造函数,好像std::dynamic_extent是在4-6中使用的。但在这些构造函数中,大小有一个必需的模板参数 - std::size_t N。对我来说,这意味着大小/计数/长度在编译时是已知的。那么到底是什么std::dynamic_extent?
C++20std::span是一个非常好的编程接口。但是似乎没有一种简单的方法来获得跨度。这是我想要做的:
#include <iostream>
#include <span>
#include <string>
#include <vector>
void print(std::span<std::span<wchar_t>> matrix) {
for (auto const& str : matrix) {
for (auto const ch : str) {
std::wcout << ch;
}
std::wcout << '\n';
}
}
int main() {
std::vector<std::wstring> vec = {L"Cool", L"Cool", L"Cool"};
print(vec);
}
Run Code Online (Sandbox Code Playgroud)
这不编译。我该怎么做?
在阅读std::span的文档时,我发现没有方法可以从std::span<T>.
您能建议一种方法来解决我的问题吗?
我的问题的大局(我在另一个问题中问:How to instantiate a std::basic_string_view with custom class T,我得到 is_trivial_v<_CharT> 断言错误)是我想要一个std::basic_string_view<Token>,而这Token不是一个微不足道的问题类,所以我不能使用std::basic_string_view,有人建议我改用std::span<Token>。
由于basic_string_view有一个名为删除第一个元素的方法remove_prefix,而我也需要此类函数,因为我想用作std::span<Token>解析器输入,因此令牌将被匹配,并一个接一个地消耗。
谢谢。
编辑 2023-02-04
我尝试派生一个名为Spanfrom的类std::span,并添加remove_prefix成员函数,但看起来我仍然存在构建问题:
#include <string_view>
#include <vector>
#include <span>
// derived class, add remove_prefix function to std::span
template<typename T>
class Span : public std::span<T>
{
public:
// Inheriting constructors
using std::span<T>::span;
// add a public function which is similar to …Run Code Online (Sandbox Code Playgroud) 即将推出的 C++20 的这种使用是否std::span正确并且没有开销来包装命令行参数?
#include <iostream>
#include <span>
int main(int argc, const char* argv[])
{
for (auto s : std::span { argv, static_cast<std::size_t>(argc) })
std::cout << s << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如果它是正确的,我可以进一步使用 withstd::string_view吗?
我希望能够将我的自定义容器传递给这个std::span构造函数:
template< class R >
explicit(extent != std::dynamic_extent)
constexpr span( R&& range );
Run Code Online (Sandbox Code Playgroud)
我需要向自定义类添加什么,以使其满足能够将其传递给std::span接收范围的构造函数的要求?
例如,std::vector我们可以这样做:
std::vector<int> v = {1, 2, 3};
auto span = std::span{v};
Run Code Online (Sandbox Code Playgroud)
我已经将这些添加到我的自定义类中:
Type* begin()
{
return m_Data;
}
Type* end()
{
return m_Data + m_Length;
}
const Type* data() const
{
return m_Data;
}
size_t size() const
{
return m_Length;
}
Run Code Online (Sandbox Code Playgroud)
...这反过来又允许我使用基于范围的循环,std::data(my_container)以及std::size(my_container). 我还缺少什么才能将容器传递给std::span构造函数?是否需要实现更复杂的迭代器?
我有一个带有成员变量的类std::vector。我还有一个成员函数,它采用std::vector由两个size_t参数指定的连续范围,并对其执行一些操作。
class MyClass {
std::vector<int> objects;
public:
void func(size_t start_index, size_t end_index);
}
Run Code Online (Sandbox Code Playgroud)
现在,我想size_t用单个参数替换两个std::span参数,以提高安全性、可读性和可维护性。然而,有一个障碍:在我的函数中,我需要能够恢复原始std::vector. 就像这样,我需要能够找到std::span原始数组中的开始位置。有没有办法做到这一点?如果没有,那么我是否别无选择,只能使用我原来笨重的设计?
objects.begin()(我最初尝试通过从我拥有的参数begin()的迭代器中减去来恢复第一个索引std::span,但这导致了编译错误。)
此示例程序无法编译,因为transform_view无法转换为std::span:
class Foo {
private:
std::vector<std::string> strings = { "a", "b", "c" };
public:
std::span<const char*> getStrings() {
return strings | std::views::transform([](const std::string& str) { return str.c_str(); });
}
};
int main() {
Foo foo;
auto strings = foo.getStrings();
for (auto s : strings)
std::cout << s << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我知道还不可能构造容器(如std::vector),但是我不太明白,为什么不能从中构造 a std::span。我找到了这个答案,即目前唯一可以从任意范围构建的容器是std::span,所以我希望上面的例子能够工作。
有没有办法从范围创建跨度?或者有没有其他方法可以从方法返回通用视图,而不使用auto(虚拟方法不允许)?
std::span考虑这段代码,它尝试为原始指针向量创建各种对象。
#include <vector>
#include <span>
int main()
{
struct S {};
std::vector<S*> v;
std::span<S*> span1{v};
std::span<S* const> span2{v};
std::span<const S* const> span3{v};
std::span<const S*> span4{v};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
span3编译正常,但span4失败并出现以下错误:
<source>: In function 'int main()':
<source>:58:32: error: no matching function for call to 'std::span<const main()::S*>::span(<brace-enclosed initializer list>)'
58 | std::span<const S*> span4{v};
| ^
In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/ranges:45,
from <source>:5:
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/span:231:9: note: candidate: 'template<class _OType, long unsigned int _OExtent> requires (_Extent == std::dynamic_extent || _OExtent == …Run Code Online (Sandbox Code Playgroud) 以下作品:
#include <vector>
#include <ranges>
int main() {
auto view = std::vector<int>{0,1,2,3,4};
auto s = std::span{view.begin(), view.end()};
std::vector test(view.begin(), view.end());
}
Run Code Online (Sandbox Code Playgroud)
但这并不:
#include <vector>
#include <ranges>
int main() {
auto view = std::ranges::iota_view{0, 1000};
auto s = std::span{view.begin(), view.end()};
std::vector test(view.begin(), view.end());
}
Run Code Online (Sandbox Code Playgroud)
问题是,我有一些通用代码,我想向它发送一个范围,然后在该范围上创建一个跨度。我试过发送一个vector,没问题。结果iota失败。
template <typename TRange>
requires std::ranges::random_access_range<TRange>
void Foo(TRange const & r)
{
// The algorithm starts with a full span and then partitions
auto s = std::span(r.begin(), r.end());
}
Run Code Online (Sandbox Code Playgroud)
该代码是从 boost 移植的,在那里我会使用boost::make_iterator_range() …