正在将指针转换为范围

Converting a pointer to a range

本文关键字:范围 转换 指针      更新时间:2023-10-16

这很有效:

const char* foo[] = {"This", "is", nullptr, "great"};
for (auto e : ::std::ranges::take_while_view (foo,             // <- array
([](const char* s){return s!=nullptr;})))
std::cout << e << "n";

这不是:

const char* foo[] = {"This", "is", nullptr, "great"};
for (auto e : ::std::ranges::take_while_view (&foo[0],         // <- pointer
([](const char* s){return s!=nullptr;})))
std::cout << e << "n";
error: no matching function for call to ‘take_while_view(const char**,
main(int, char**)::<lambda(const char*)>)’

我们是否可以使用标准库类型和函数,强制C++将指针视为一种半无限范围,然后我们可以进一步限制它?

我总是可以创建自己的类来表示半无限视图,但我宁愿在标准库中找到解决方案。

有一种方法可以从不同的部分组装这样一个范围,但不能隐式地将T*视为一个。

您要做的是使用unreachable_sentinel_t作为sentinel类型,从指针构造一个subrange。所以你可以将这样一个函数编码为:

template<typename T>
auto inf_ptr_range(T *ptr)
{
return std::ranges::subrange(ptr, std::unreachable_sentinel_t{});
}

你可以在你的代码中使用它:

const char* foo[] = {"This", "is", nullptr, "great"};
for (auto e : ::std::ranges::take_while_view (
inf_ptr_range(foo),
([](const char* s){return s!=nullptr;})))
std::cout << e << "n";

或者使用视图样式表示法:

int main()
{
const char* foo[] = {"This", "is", nullptr, "great"};
for (auto e : inf_ptr_range(foo) | std::views::take_while(
[](const char* s){return s!=nullptr;}))
std::cout << e << "n";
}

使用iota制作无限范围,然后将其切断。

auto my_range =
std::views::iota(&foo[0])
| std::views::transform([](auto p) -> auto& { return *p; })
| std::views::take_while([](auto p) { return p != nullptr; });
for(auto &ptr : my_range) {
std::cout << ptr << "n";
ptr = "really";
}
for(auto &ptr : my_range) std::cout << ptr << "n"; // mutation works!
std::cout << foo[3] << "n";

Godbolt

我相信这是安全的(take_while"保护"transformiota,这样我们就永远不会试图计算&foo[0] + 5,甚至访问foo[3](。