std::filesystem::directory_iterator 之类的迭代器可以在循环外使用吗?

Can an iterator such as std::filesystem::directory_iterator be used outside of a loop?

我正在尝试了解如何在 C++ 中使用迭代器之类的东西,并且特别想更好地了解 std::filesystem::directory_iterator。

我理解这样简单的例子:

#include <iostream>
#include <filesystem>
#include <string>

void doSomething(std::string filename)
{
    std::cout << filename;
};

int main()
{
    auto iterator = std::filesystem::directory_iterator("c:/somefolder");
    for (auto& i : iterator)
    {
        doSomething(std::filesystem::path(i.path()).filename().string());
    }
}

但是很多遗留代码并不是在这样一个紧密的循环中编写的。是否可以以类似于 WinAPI FindNextFile() 的方式使用 directory_iterator?

与此类似的内容:

std::string getNextFilename(std::string path)
{
    // Notice the actual filesystem access code is neatly packed away in a replaceable function suitable for a HAL.
    static auto iterator = std::filesystem::directory_iterator(path);
    return std::filesystem::path(iterator.path()).filename().string();
}

int main()
{
    while (std::string fileName = getNextFilename("c:/somefolder"))
    {
        doSomething(fileName);
    }

    // or

    std::string fileFirst  = getNextFilename("c:/somefolder");
    std::string fileSecond = getNextFilename("c:/somefolder");
    std::string fileLast   = getNextFilename("c:/somefolder");

}

请回答:

  1. 一般迭代器,能不能这样用,为什么?
  2. 具体如何一次执行一个 file/directory 的这种目录查找。

edit1:澄清标题。

手动递增迭代器很容易(因为这也是基于范围的 for 循环所做的)。但是您需要相应地调整其他代码,因为 std::string 没有 operator bool。一种可能的解决方案(仅略微修改原始代码,仍然包含所有问题)可能如下所示(使用 std::optional<std::string> 启用返回“结束”条件):

#include <iostream>
#include <filesystem>
#include <string>
#include <optional>

void doSomething(std::string filename)
{
    std::cout << filename;
};

std::optional<std::string> getNextFilename(std::string path)
{
    static auto iterator = std::filesystem::directory_iterator(path);
    if (iterator != std::filesystem::directory_iterator()) {
        auto filename = std::filesystem::path(iterator->path()).filename().string();
        ++iterator; // advance iterator to next entry in directory
        return filename; // uses implicit constructor of `std::optional`
    } else {
        return {}; // return empty optional if we reached end of directory
    }
}

int main()
{
    while (auto fileName = getNextFilename("c:/somefolder"))
    {
        doSomething(*fileName); // dereference optional to get value
    }

    // or

    auto fileFirst  = getNextFilename("c:/somefolder");
    auto fileSecond = getNextFilename("c:/somefolder");
    auto fileLast   = getNextFilename("c:/somefolder");

}

假设您想要或多或少 drop-in 替代 FindFirstFile/FindNextFile,解决方案可能如下所示:

struct HANDLE{
    std::filesystem::directory_iterator it;
};
bool FindNextFile(HANDLE &handle, std::string& output) {
    if(handle.it == std::filesystem::directory_iterator{}) return false;
    output=handle.it->path().string();
    handle.it++;
    return true;
}
HANDLE FindFirstFile(std::string input, std::string& output) {
    HANDLE h;
    h.it=std::filesystem::directory_iterator{input};
    FindNextFile(h,output);
    return h;
}
std::filesystem::path my_path("C:/");
for (std::filesystem::directory_iterator itt(my_path);
     itt != std::filesystem::directory_iterator(); itt++)
    {
         const std::filesystem::directory_entry& entr = *itt;
         std::string filename = entr.path().string();
    }

这里好像没有begin()end()。也没有 -- 运算符。因此,例如从头到尾迭代它似乎是不可能的。也没有 size() 功能