gpt4 book ai didi

c++ - 为什么我不能将这个转换后的 directory_iterator 插入到一个 vector 中?

转载 作者:行者123 更新时间:2023-12-04 16:24:06 27 4
gpt4 key购买 nike

我正在尝试使用其 insert(const_iterator pos, InputIt first, InputIt last) 将转换后的目录条目范围插入 vector 中成员函数模板。
不幸的是,我无法在 GCC 下编译以下代码 11.1.0 ,根据 https://en.cppreference.com/w/cpp/compiler_support 应该有范围支持.

#include <filesystem>
#include <vector>
#include <ranges>
#include <iterator>

namespace fs = std::filesystem;
namespace ranges = std::ranges;
namespace views = std::views;

// no solution
namespace std {
template <typename F>
struct iterator_traits<ranges::transform_view<ranges::ref_view<fs::directory_iterator>, F>> {
using iterator_category = std::input_iterator_tag;
};
}

int main() {
std::vector<fs::path> directory_tree;

auto subdir = fs::directory_iterator(".");
ranges::input_range auto subdir_names = subdir
| views::transform([](const auto& entry) { return entry.path(); /* can be more complex*/ })
| views::common;

// replacing subdir_names with subdir works
std::input_iterator auto b = ranges::begin(subdir_names);
std::input_iterator auto e = ranges::end(subdir_names);
directory_tree.insert(
directory_tree.begin(),
b,
e
);
}
错误信息主要说:
error: no matching function for call to 'std::vector<std::filesystem::__cxx11::path>::insert(std::vector<std::filesystem::__cxx11::path>::iterator, std::ranges::transform_view<std::ranges::ref_view<std::filesystem::__cxx11::directory_iterator>, main()::<lambda(const auto:16&)> >::_Iterator<false>&, std::ranges::transform_view<std::ranges::ref_view<std::filesystem::__cxx11::directory_iterator>, main()::<lambda(const auto:16&)> >::_Iterator<false>&)'
再往下:
error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<std::ranges::transform_view<std::ranges::ref_view<std::filesystem::__cxx11::directory_iterator>, main()::<lambda(const auto:15&)> >::_Iterator<false> >’
我曾尝试将上述特化添加到 std::iterator_traits对于相关的迭代器类型,但无济于事。我想了解为什么这不能编译,如果可能的话,如何修复它。我想避免创建临时 vector 。
让我知道是否需要更多 gcc 的错误消息。

最佳答案

fs::directory_iterator是输入范围。这意味着当您通过 transform 对其进行调整时你仍然会得到一个输入范围(自然)。这个转换范围的迭代器有一个后缀 operator++返回 void .
这可以说是 C++98 迭代器模型中的一个缺陷,它甚至仍然需要输入迭代器有一个后缀 operator++返回原始类型。即使这必然是悬空操作。在C++20迭代器模型中,postfix-increment可以返回void用于输入迭代器。
因此,您返回的转换范围( views::common 是空操作,它已经是 common )是 C++20 输入范围(正如您正在验证的那样),但它不是任何类型的 C++98/C++17 范围,因为它的迭代器由于后缀增量规则甚至不满足 Cpp17InputIterator - 所以它的迭代器甚至不费心提供 iterator_category .
这使得:

directory_tree.insert(directory_tree.begin(), b, e);
失败,因为这个函数需要满足 Cpp17InputIterator 和 b 的类型和 e不要。

解决方法是改为执行以下操作:
ranges::copy(subdir_names, std::inserter(directory_tree, directory_tree.begin()));
或者甚至将两个步骤结合起来:
ranges::copy(subdir
| views::transform([](const auto& entry) { return entry.path(); /* can be more complex*/ }),
std::inserter(directory_tree, directory_tree.begin())
);
在这里,我们只要求源范围为 C++20 input_range (它是)。
目的是很快您将能够编写:
directory_tree.insert_range(
directory_tree.begin(),
subdir
| views::transform([](const auto& entry) { return entry.path(); }));
但这不会直到 C++23。

关于c++ - 为什么我不能将这个转换后的 directory_iterator 插入到一个 vector 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68673969/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com