【问题标题】:How to use recursive_directory_iterator with algorithm library and std::remove_if in particular?如何将 recursive_directory_iterator 与算法库和 std::remove_if 一起使用?
【发布时间】:2017-11-15 16:23:30
【问题描述】:

我想使用标准算法从递归目录列表中过滤掉一些条目。假设只留下常规文件。 STL 中的一些算法确实有效,例如std::count_if,但其他人,例如 std::remove_if,则不这样做。

它应该工作还是 recursive_directory_iterator 故意不(完全)与 STL 兼容?

鉴于recursive_directory_iterator,有没有办法仅以函数式编程风格处理常规文件(以及之后可能链接其他过滤器)?

#include <algorithm>
#include <experimental/filesystem>
#include <iostream>

namespace fs = std::experimental::filesystem;

int main()
{
  { // count_if is fine
    auto dir_listing = fs::recursive_directory_iterator("/tmp/myfiles");
    auto n = std::count_if(begin(dir_listing), end(dir_listing), [](auto &p) { return fs::is_regular_file(p); });
    std::cout << n << '\n';
  }

  { // remove_if does not even compile
    auto dir_listing = fs::recursive_directory_iterator("/tmp/myfiles");
    auto my_files = std::remove_if(begin(dir_listing), end(dir_listing), [](const fs::path &p) { return !fs::is_regular_file(p); });
    for (auto &f : my_files)
    {
      std::cout << f << '\n';
    }
  }
}

使用 gcc-7 编译会导致错误(clang-5 也是​​如此)

g++-7 myfiles.cpp -std=c++1z -lstdc++fs
...
/usr/include/c++/7/bits/stl_algo.h:871:16: error: passing ‘const std::experimental::filesystem::v1::directory_entry’ as ‘this’ argument discards qualifiers [-fpermissive]
      *__result = _GLIBCXX_MOVE(*__first);

在添加 -fpermissive 之后,它只是段错误。

【问题讨论】:

标签: c++ algorithm stl c++17


【解决方案1】:

std::remove_if 需要前向迭代器,指向移动可分配的值。 recursive_directory_iterator 是一个输入迭代器,它指向的值是 const(所以不能移动赋值)。

我不确定您到底要做什么,但 std::remove/remove_if 用于从集合中删除项目。并非所有迭代器都指向集合,recursive_directory_iterator 就是这种情况。

如果您尝试将其用作可能转发给其他算法的过滤器,不幸的是标准库对此没有直接支持。您可能做的最好的事情(使用标准库)是使用 remove_copy_ifback_inserter 将元素过滤到向量中,然后对该向量进行进一步处理。

std::vector<fs::path> paths;
std::remove_copy_if(begin(dir_listing), end(dir_listing), std::back_inserter(paths),
    [](const fs::path& p) {
        return !fs::is_regular_file(p);
    });

【讨论】:

  • 正是我要写的。 ;-) @sciamano 看看iterator categories 会有所帮助。如果一个函数需要某个类别,您只能向它传递一个相同或限制较少的类别(位于预期类别左侧的那些)的迭代器。此外,begin(dir_listing)end(dir_listing) 的使用暗示了对recursive_directory_iterator 的误解。它不是像std::vector 这样的集合。
  • @zett42:它不是一个集合,但它仍然支持beginendbegin 返回迭代器本身,end 返回默认构造的迭代器。 en.cppreference.com/w/cpp/filesystem/…
  • 有趣,虽然感觉有点奇怪。它可能只是为了方便起见,因为范围尚未成为标准。
  • @zett42:是的,主要是因为你可以将它传递给基于范围的 for 循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-07
  • 2010-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 2020-12-13
相关资源
最近更新 更多