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
Post a Comment