c++ - Using boost range adaptors with a directory iterator range -


edit: added solutions below question, based on jonathan's answer

i want have list of regular files name pattern in given directory. took 1 of examples boost.filesystem (boost 1.53) , modified it. here working version of want:

#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';       // want replace part:         std::list<directory_entry> datfiles;         for(directory_iterator it(p); != directory_iterator(); ++it)         {           if (is_regular_file(*it) && (extension(*it) == ".dat"))           {             datfiles.push_back(*it);           }         }       // part replaced ends here         boost_foreach(const directory_entry& de, datfiles)         {           cout << de << '\n';         }       }     }   }    catch (const filesystem_error& ex)   {     cout << ex.what() << '\n';   }    return 0; } 

this appends entry of files ending .dat list of directory entries. need more pattern matching later. tried same thing ranges, , failed. reduced task copying directory entries doesn't compile:

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

i wrote way because (tut3.cpp boost.filesystem)

directory_iterator::value_type directory_entry

so copy can iterate on range, entries , store them in list. however, i'm getting lots of error messages gcc:

in file included boost_1_53_0/boost/type_traits/decay.hpp:18:0,                  boost_1_53_0/boost/filesystem/path_traits.hpp:22,                  boost_1_53_0/boost/filesystem/path.hpp:25,                  boost_1_53_0/boost/filesystem.hpp:16,                  ~/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 ‘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 ‘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 ‘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 ‘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 ‘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 ‘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 ‘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 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 boost_1_53_0/boost/range/algorithm.hpp:53:0,                  ~/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 here boost_1_53_0/boost/range/algorithm/copy.hpp:34:59: error: no matching function call ‘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 call ‘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] 

i wasn't able filter out relevant lines, think possible filter files using range adaptors (i don't want copy range, after all). impression somewhere along way datfiles.begin() doesn't satisfy concept needed copy algorithm.


some of solutions

here of solutions (including filtering) came with, based on jonathan's answer.

using global predicate function bool isdatfile(const path& p):

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

i preferred local function, though, tried that. 1 checking if directory entry regular file, static cast needed because is_regular_file overloaded:

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

checking right extension in range adaptor bit hard, added local function:

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)); 

and "one-liner" using bind:

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)); 

this line hitting most vexing parse:

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

that declares function not object.

you can change to:

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

or in c++11:

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

but it's better use factory function it:

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

by using make_iterator_range don't need name type of iterator, deduced argument types.

the other problem you're writing empty list, undefined behaviour, should use insert iterator call push_back() in working code. putting together:

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

in c++11 it's more concise:

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

now add filter pretty easily:

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

Comments

Popular posts from this blog

SPSS keyboard combination alters encoding -

Add new record to the table by click on the button in Microsoft Access -

CSS3 Transition to highlight new elements created in JQuery -