在一个简单的views适配器管道中,调用一个gen函数来生成一系列值(使用内部状态),然后对其进行过滤。
令人惊讶和违反直觉的(至少对我来说)是这样的事实:生成器函数在每次迭代中被调用两次,因此对同一过滤器的下一次检查失败(过滤后的值不会在管道中重用)。
您知道这是否是正确的预期行为(以及为什么)?
libstdc++在 GCC 10.3、11.1 和 trunk(代码)以及range-v3GCC 和 clang(代码)中进行了测试。
int main() {
int n = 0;
auto gen = [&n]() {
auto result = ++n;
std::cout << "Generate [" << result << "]\n";
return result;
};
auto tmp =
ranges::views::iota(0)
| ranges::views::transform([gen](auto &&) { return gen(); })
| ranges::views::filter([](auto &&i) {
std::cout << "#1 " << i << " " << (i % 2) << "\n";
return (i …Run Code Online (Sandbox Code Playgroud) C++20带来了更强大的迭代器系统,其中之一就是iterator_concept在iterator_category.
我发现C++20 中很多迭代器的iterator_concept和iterator_category是不一致的。以最著名iota_view的为例:
using R = decltype(views::iota(0));
static_assert(random_access_range<R>);
using I = ranges::iterator_t<R>;
static_assert(same_as<typename I::iterator_category, input_iterator_tag>);
static_assert(same_as<typename I::iterator_concept, random_access_iterator_tag>);
Run Code Online (Sandbox Code Playgroud)
虽然是Rmodels random_access_range,但iterator_category它的迭代器的the只是一个input_iterator_tag,与iterator_concept.
为什么C++20引入iterator_concept?它的目的是什么?如果我实现我自己的迭代器,我该如何界定iterator_concept和iterator_category正确?是否iterator_category仍然在C ++ 20的意思?
我已经阅读了最新的草案,其中lazy_split_view添加了内容。
但后来我发现它split_view改名为lazy_split_view,而且又split_view更新了。
libstdc++最近还通过使用GCC Trunk版本https://godbolt.org/z/9qG5T9n5h实现了这一点
我这里有一个简单的天真的程序,它显示了两个视图的用法,但我看不到它们的区别:
#include <iostream>
#include <ranges>
int main(){
std::string str { "one two three four" };
for (auto word : str | std::views::split(' ')) {
for (char ch : word)
std::cout << ch;
std::cout << '.';
}
std::cout << '\n';
for (auto word : str | std::views::lazy_split(' ')) {
for (char ch : word)
std::cout << ch;
std::cout << '.';
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
one.two.three..four.
one.two.three..four. …Run Code Online (Sandbox Code Playgroud) 否则,如果 Ranges::disable_sized_range<std::remove_cv_t<T>> 为 false,则 size(t) 转换为其衰减类型,并且转换后的表达式有效且具有类似整数的类型,其中重载解析通过以下命令执行以下候选人:
void size(auto&) = delete;void size(const auto&) = delete;1
class Test {
friend size_t size(/*const*/ Test&) {
return 0;
}
};
int main() {
std::ranges::size(Test{});
// no matching function error when adding the `const` qualifier
}
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/79e5vrKrT
一般来说,方法size不需要像std::size.
为什么会有这样的限制呢std::ranges::size?(好像只有非会员版才能执行。)
我有一个返回小写字符串的函数:
constexpr auto string_to_lower_case(const std::string& string) {
return string
| std::views::transform(std::tolower)
| std::views::transform([](const auto& ascii) { return static_cast<char>(ascii); });
}
Run Code Online (Sandbox Code Playgroud)
我希望当我传递"SOME"or时该函数返回相同的结果const std::string some("SOME"),但事实并非如此。当我尝试打印 的结果时string_to_lower_case("SOME"),我检索到一个空控制台( 的输出string_to_lower_case(some)是正确的)
const std::string some("SOME");
for (const auto& ch : string_to_lower_case(some))
std::cout << ch;
Run Code Online (Sandbox Code Playgroud) 自从std::generator正在进入 CPP23,我正在尝试 MSVC 的不完整版本。
然而,我注意到,yield与 一起使用时,它似乎恰好丢失了一个std::views::take。这是示例:
#include <iostream>
#include <ranges>
#include <experimental/generator>
std::experimental::generator<int> GeneratorFn(void) noexcept
{
co_yield 1;
co_yield 2;
co_yield 3;
co_yield 4;
co_yield 5;
co_yield 6;
co_yield 7;
co_yield 8;
co_yield 9;
co_return;
}
int main(int argc, char** args) noexcept
{
auto Ret = GeneratorFn();
for (auto&& i : Ret | std::views::take(2))
std::cout << i << '\n';
for (auto&& i : Ret | std::views::take(3))
std::cout << i << '\n';
for (auto&& i …Run Code Online (Sandbox Code Playgroud) 在我的回答中,巴里指出最好打电话,views::transform(&Planter::getPlants)因为views::transform([](Planter const& planter){...不小心复制了。
#if 1
auto plants = planters
| std::views::transform([](Planter const& planter){ return planter.getPlants();})
| std::views::join
| std::views::common
;
// Plant copy constructor
// Plant copy constructor
// Plant copy constructor
// Plant copy constructor
// Plant copy constructor
#else
auto plants = planters
| std::views::transform(&Planter::getPlants)
| std::views::join
;
#endif
// Plant copy constructor
// Plant copy constructor
Run Code Online (Sandbox Code Playgroud)
这Plant是一个围绕的包装器int,Planter也是一个围绕的包装器std::vector<int>。
boost::join在混合 的输出时,我遇到了意外的行为std::views::transform(如下所示)。编译器不会发出任何警告。幸运的是,地址清理程序可以检测到get2b().
该get1b()函数遵循与 相同的模式get2b(),但该代码工作正常。考虑到 UB 的可能性,我如何确定构造的范围是合法的?我偏执的一面想get1b()写成return std::move(rng) | ...。
https://www.godbolt.org/z/Y77YW3jYb
#include <array>
#include <ranges>
#include <algorithm>
#include <iostream>
#include <iterator>
#include "boost/range/join.hpp"
#include "boost/range/adaptor/transformed.hpp"
inline auto square = [](int x) { return x*x; };
struct A {
std::array<std::vector<int>, 3> m_data{ std::vector{1, 2}, std::vector{3, 4, 5}, std::vector{6} };
auto join1() const { return m_data | std::views::join; }
auto join2() const { return boost::join(m_data[0], boost::join(m_data[1], m_data[2])); }
auto get1a() …Run Code Online (Sandbox Code Playgroud) 有一个相当典型的任务是同时对两个数组进行排序,假设数组的相同索引元素形成虚拟对,并对其进行排序。这样的问题至少在 10 年前就出现过:boost zip_iterator 和 std::sort
现在这个任务可以使用range-v3库来解决:
#include <array>
#include <range/v3/all.hpp>
int main() {
auto x = std::array{ 3, 2, 4, 1 };
auto y = std::array{'A', 'B', 'C', 'D'};
ranges::sort( ranges::views::zip( x, y ) );
// here x = {1,2,3,4}, y={'D','B','A','C'}
}
Run Code Online (Sandbox Code Playgroud)
在线演示: https: //gcc.godbolt.org/z/WGo4vGsx5
在 C++23 中出现了std::ranges::zip_view,我的期望是可以仅使用标准库编写相同的程序:
#include <array>
#include <ranges>
#include <algorithm>
int main() {
auto x = std::array{ 3, 2, 4, 1 };
auto y = std::array{'A', 'B', 'C', 'D'};
std::ranges::sort( std::views::zip( …Run Code Online (Sandbox Code Playgroud) 目前只有 MSVC 支持 nifty helper ranges::to,所以我无法在另一个编译器中验证这一点。基本上,我有一个 STL 容器的类型别名,一旦我尝试将其传递给ranges::to,编译就会失败。那么这是有效的用法吗?为什么下面的第二个(注释掉的)示例无法编译?
#include <ranges>
#include <vector>
#include <iostream>
template <typename T>
using Vec = std::vector<T>;
int main(int argc, char* argv[]) {
auto vec = std::views::iota(1, 10) | std::ranges::to<std::vector>();
//auto vec = std::views::iota(1, 10) | std::ranges::to<Vec>(); // C2440: cannot convert from 'void' to 'std::vector'.
for (auto& v : vec)
std::cout << v << ", ";
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)