在移出界限之前停止directory_iterator

时间:2016-11-24 14:52:45

标签: c++ c++17

我试图遍历一个目录并读取里面的图像,同时允许跳过每个第n个文件。

我的代码目前看起来像这样:

// Count number of files in directory and reserve memory (take skipped slices into account)
std::experimental::filesystem::directory_iterator it_begin{path};
int count = count_if(it_begin, std::experimental::filesystem::directory_iterator(), [](const std::experimental::filesystem::directory_entry & d) {return !is_directory(d.path());});
auto maxCount = count - (count % (1 + skipSlices));
m_imageStack.reserve(maxCount);

// Read image stack and check for validity
int n = 0;
for (std::experimental::filesystem::v1::directory_iterator it(path); it != std::experimental::filesystem::v1::directory_iterator(); std::advance(it, 1 + skipSlices))
{
    std::string filename{std::experimental::filesystem::v1::path(*it).string()};
    cv::Mat image = cv::imread(filename);
    m_imageStack.push_back(image);

    n = n + 1 + skipSlices;
    if (n == maxCount) break;
}

如果skipSlices = 1,我只想读取每个第二张图像等。为了不移出界限,我在for循环中添加了一个中断条件。我现在的解决方案非常糟糕,我想摆脱中断,而是在for-loop中使用更正确的停止条件。但是,我无法找到一种方法来告诉迭代器在推进太多之前停止。有什么想法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

只需编写一个限制的advance版本。

namespace detail {
    template<class It, class Dist>
    void advance_with_limit_impl(It& it, It end, Dist n, std::random_access_iterator_tag) {
        if(n > 0) it += std::min(end - it, n);
        else it += std::max(end - it, n);
    }

    template<class It, class Dist>
    void advance_with_limit_impl(It& it, It end, Dist n, std::bidirectional_iterator_tag) {
        if(n > 0) { while(n != 0 && it != end) { --n; ++it; } }
        else { while (n != 0 && it != end) { ++n; --it; } }
    }

    template<class It, class Dist>
    void advance_with_limit_impl(It& it, It end, Dist n, std::input_iterator_tag) {
        while(n != 0 && it != end) { --n; ++it; }
    }
}

template<class It>
void advance_with_limit(It& it, It end, 
                        typename std::iterator_traits<It>::difference_type n) {
    detail::advance_with_limit_impl(it, end, n, 
                               typename std::iterator_traits<It>::iterator_category());
}

然后使用advance_with_limit(it, {}, 1 + skipSlices)