簡體   English   中英

使用具有目錄迭代器范圍的boost范圍適配器

[英]Using boost range adaptors with a directory iterator range

編輯:根據Jonathan的回答,我在我的問題下面添加了一些解決方案

我想在給定目錄中有一個具有特定名稱模式的常規文件列表。 我從boost.filesystem (boost 1.53)中獲取了一個示例並對其進行了修改。 這是我基本上想要的工作版本:

#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

using namespace std;
using namespace boost::filesystem;

int main(int argc, char* argv[])
{
  path p ("."); // search directory

  try
  {
    if (exists(p))
    {
      if (is_directory(p))
      {
        cout << "logfiles in " << absolute(p) << '\n';
      // I want to replace this part:
        std::list<directory_entry> datFiles;
        for(directory_iterator it(p); it != directory_iterator(); ++it)
        {
          if (is_regular_file(*it) && (extension(*it) == ".dat"))
          {
            datFiles.push_back(*it);
          }
        }
      // part to be replaced ends here
        BOOST_FOREACH(const directory_entry& de, datFiles)
        {
          cout << de << '\n';
        }
      }
    }
  }

  catch (const filesystem_error& ex)
  {
    cout << ex.what() << '\n';
  }

  return 0;
}

這會將以.dat結尾的所有文件的條目附加到目錄條目列表中。 我以后需要更多模式匹配。 然后我嘗試用范圍做同樣的事情,但失敗了。 我現在將任務簡化為簡單地復制所有不編譯的目錄條目:

    // replacement starts here
        std::list<directory_entry> datFiles;
        boost::iterator_range<directory_iterator> rng(directory_iterator(p), directory_iterator());should be
        boost::copy(rng, datFiles.begin());
    // replacement ends here

我這樣寫的是因為(來自boost.filesystem的tut3.cpp)

directory_iterator :: value_type是directory_entry

因此,副本可以遍歷范圍,獲取條目並將其存儲在我的列表中。 但是,我從gcc收到了很多錯誤消息:

In file included from boost_1_53_0/boost/type_traits/decay.hpp:18:0,
                 from boost_1_53_0/boost/filesystem/path_traits.hpp:22,
                 from boost_1_53_0/boost/filesystem/path.hpp:25,
                 from boost_1_53_0/boost/filesystem.hpp:16,
                 from ~/20130519_searchDatFiles/main.cpp:3:
boost_1_53_0/boost/mpl/eval_if.hpp: In instantiation of ‘boost::mpl::eval_if_c<false, boost::range_const_iterator<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())>, boost::range_mutable_iterator<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())> >’:
boost_1_53_0/boost/range/iterator.hpp:63:63:   instantiated from ‘boost::range_iterator<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())>’
boost_1_53_0/boost/range/concepts.hpp:256:72:   instantiated from ‘boost::SinglePassRangeConcept<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())>’
boost_1_53_0/boost/concept/detail/has_constraints.hpp:42:5:   instantiated from ‘const bool boost::concepts::not_satisfied<boost::SinglePassRangeConcept<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())> >::value’
boost_1_53_0/boost/concept/detail/has_constraints.hpp:45:31:   instantiated from ‘boost::concepts::not_satisfied<boost::SinglePassRangeConcept<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())> >’
boost_1_53_0/boost/mpl/if.hpp:67:11:   instantiated from ‘boost::mpl::if_<boost::concepts::not_satisfied<boost::SinglePassRangeConcept<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())> >, boost::concepts::constraint<boost::SinglePassRangeConcept<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())> >, boost::concepts::requirement<boost::concepts::failed************ boost::SinglePassRangeConcept<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())>::************> >’
boost_1_53_0/boost/concept/detail/general.hpp:50:8:   instantiated from ‘boost::concepts::requirement_<void (*)(boost::SinglePassRangeConcept<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())>)>’
boost_1_53_0/boost/range/algorithm/copy.hpp:33:1:   instantiated from ‘OutputIterator boost::range::copy(const SinglePassRange&, OutputIterator) [with SinglePassRange = boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)()), OutputIterator = std::_List_iterator<boost::filesystem::directory_entry>]’
~/20130519_searchDatFiles/main.cpp:45:42:   instantiated from here
boost_1_53_0/boost/mpl/eval_if.hpp:60:31: error: no type named ‘type’ in ‘boost::mpl::eval_if_c<false, boost::range_const_iterator<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())>, boost::range_mutable_iterator<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())> >::f_ {aka struct boost::range_mutable_iterator<boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())>}’
In file included from boost_1_53_0/boost/range/algorithm.hpp:53:0,
                 from ~/20130519_searchDatFiles/main.cpp:7:
boost_1_53_0/boost/range/algorithm/copy.hpp: In function ‘OutputIterator boost::range::copy(const SinglePassRange&, OutputIterator) [with SinglePassRange = boost::iterator_range<boost::filesystem::directory_iterator>(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)()), OutputIterator = std::_List_iterator<boost::filesystem::directory_entry>]’:
~/20130519_searchDatFiles/main.cpp:45:42:   instantiated from here
boost_1_53_0/boost/range/algorithm/copy.hpp:34:59: error: no matching function for call to ‘begin(boost::iterator_range<boost::filesystem::directory_iterator> (&)(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)()))’
boost_1_53_0/boost/range/algorithm/copy.hpp:34:59: note: candidates are:
boost_1_53_0/boost/range/begin.hpp:101:55: note: template<class T> typename boost::range_iterator::type boost::range_adl_barrier::begin(T&)
boost_1_53_0/boost/range/begin.hpp:112:61: note: template<class T> typename boost::range_iterator<const T>::type boost::range_adl_barrier::begin(const T&)
boost_1_53_0/boost/range/algorithm/copy.hpp:34:59: error: no matching function for call to ‘end(boost::iterator_range<boost::filesystem::directory_iterator> (&)(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)()))’
boost_1_53_0/boost/range/algorithm/copy.hpp:34:59: note: candidates are:
boost_1_53_0/boost/range/end.hpp:95:55: note: template<class T> typename boost::range_iterator::type boost::range_adl_barrier::end(T&)
boost_1_53_0/boost/range/end.hpp:106:61: note: template<class T> typename boost::range_iterator<const T>::type boost::range_adl_barrier::end(const T&)
boost_1_53_0/boost/range/algorithm/copy.hpp:35:1: warning: control reaches end of non-void function [-Wreturn-type]

我真的無法過濾掉相關的行,但我認為可以使用范圍適配器過濾文件(畢竟我不只是想復制范圍)。 我的印象是,在某些地方, datFiles.begin()不滿足復制算法所需的概念。


我的一些解決方案

根據Jonathan的回答,我提出了一些解決方案(包括過濾)。

使用全局謂詞函數bool isDatFile(const path& p)

std::list<directory_entry> datFiles;
boost::copy(rng | boost::adaptors::filtered(isDatFile), std::back_inserter(datFiles));

不過,我更喜歡本地功能,所以我試過了。 這個只是檢查目錄條目是否是常規文件,因為is_regular_file被重載,所以需要靜態is_regular_file

std::list<directory_entry> datFiles;
boost::copy(rng
            | boost::adaptors::filtered(static_cast<bool (*)(const path&)>(&is_regular_file)),
            std::back_inserter(datFiles));

在范圍適配器中檢查正確的擴展也有點困難,所以我添加了一個本地函數:

std::list<directory_entry> datFiles;
bool BOOST_LOCAL_FUNCTION(const path& p)
{
  return (is_regular_file(p) && (extension(p) == string(".dat")));
} BOOST_LOCAL_FUNCTION_NAME(isDatFile_l)
boost::copy(rng
            | boost::adaptors::filtered(isDatFile_l),
            std::back_inserter(datFiles));

最后使用bind的“one-liner”:

std::list<directory_entry> datFiles;
boost::copy(rng
            | boost::adaptors::filtered(static_cast<bool (*)(const path&)>(&is_regular_file))
            | boost::adaptors::filtered(boost::bind(std::equal_to<path>(), boost::bind(extension, _1), path(".dat"))),
            std::back_inserter(datFiles));

這條線擊中的是令人煩惱的解析

boost::iterator_range<directory_iterator> rng(directory_iterator(p), directory_iterator());

聲明函數不是對象。

您可以將其更改為:

boost::iterator_range<directory_iterator> rng = boost::iterator_range<directory_iterator>(directory_iterator(p), directory_iterator());

或者在C ++ 11中:

auto rng = boost::iterator_range<directory_iterator>(directory_iterator(p), directory_iterator());

但是使用工廠功能更好:

boost::iterator_range<directory_iterator> rng = boost::make_iterator_range(directory_iterator(p), directory_iterator());

通過使用make_iterator_range您不需要命名迭代器的類型,它將從參數類型中推導出來。

另一個問題是你正在寫一個空列表,這是未定義的行為,你應該使用插入迭代器來調用push_back()就像在你的工作代碼中一樣。 把它們放在一起:

std::list<directory_entry> datFiles;
boost::copy( boost::make_iterator_range(directory_iterator(p), directory_iterator()),
             std::back_inserter(datFiles) );

在C ++ 11中,它更簡潔:

std::list<directory_entry> datFiles;
boost::copy( boost::make_iterator_range(directory_iterator(p), {}),
             std::back_inserter(datFiles) );

現在您可以非常輕松地添加過濾器:

std::list<directory_entry> datFiles;
boost::copy( boost::make_iterator_range(directory_iterator(p), {}) | some_dir_filter,
             std::back_inserter(datFiles) );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM