title: Using boost range adaptors with a directory iterator range
body: <p><strong>Edit: I added some solutions below my question, based on Jonathan's answer</strong></p>
  
  <p>I want to have a list of regular files with a certain name pattern in a given directory. I took one of the examples from <a href="http://www.boost.org/doc/libs/1_53_0/libs/filesystem/doc/index.htm" rel="nofollow">boost.filesystem</a> (boost 1.53) and modified it. Here is a working version of what I basically want:</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;boost/filesystem.hpp&gt;
  #include &lt;boost/foreach.hpp&gt;
  
  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 &lt;&lt; "logfiles in " &lt;&lt; absolute(p) &lt;&lt; '\n';
        // I want to replace this part:
          std::list&lt;directory_entry&gt; datFiles;
          for(directory_iterator it(p); it != directory_iterator(); ++it)
          {
            if (is_regular_file(*it) &amp;&amp; (extension(*it) == ".dat"))
            {
              datFiles.push_back(*it);
            }
          }
        // part to be replaced ends here
          BOOST_FOREACH(const directory_entry&amp; de, datFiles)
          {
            cout &lt;&lt; de &lt;&lt; '\n';
          }
        }
      }
    }
  
    catch (const filesystem_error&amp; ex)
    {
      cout &lt;&lt; ex.what() &lt;&lt; '\n';
    }
  
    return 0;
  }
  </code></pre>
  
  <p>This appends the entry of all files ending with <code>.dat</code> to the list of directory entries. I need more pattern matching later. I then tried to do the same thing with ranges, and failed. I now reduced the task to simply copying all directory entries which also doesn't compile:</p>
  
  <pre><code>    // replacement starts here
          std::list&lt;directory_entry&gt; datFiles;
          boost::iterator_range&lt;directory_iterator&gt; rng(directory_iterator(p), directory_iterator());should be
          boost::copy(rng, datFiles.begin());
      // replacement ends here
  </code></pre>
  
  <p>I wrote it this way because (tut3.cpp from boost.filesystem)</p>
  
  <blockquote>
    <p>directory_iterator::value_type is directory_entry</p>
  </blockquote>
  
  <p>So that copy can iterate over the range, get entries and store them in my list. However, I'm getting lots of error messages from gcc:</p>
  
  <pre><code>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&lt;false, boost::range_const_iterator&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt;, boost::range_mutable_iterator&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt; &gt;’:
  boost_1_53_0/boost/range/iterator.hpp:63:63:   instantiated from ‘boost::range_iterator&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt;’
  boost_1_53_0/boost/range/concepts.hpp:256:72:   instantiated from ‘boost::SinglePassRangeConcept&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt;’
  boost_1_53_0/boost/concept/detail/has_constraints.hpp:42:5:   instantiated from ‘const bool boost::concepts::not_satisfied&lt;boost::SinglePassRangeConcept&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt; &gt;::value’
  boost_1_53_0/boost/concept/detail/has_constraints.hpp:45:31:   instantiated from ‘boost::concepts::not_satisfied&lt;boost::SinglePassRangeConcept&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt; &gt;’
  boost_1_53_0/boost/mpl/if.hpp:67:11:   instantiated from ‘boost::mpl::if_&lt;boost::concepts::not_satisfied&lt;boost::SinglePassRangeConcept&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt; &gt;, boost::concepts::constraint&lt;boost::SinglePassRangeConcept&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt; &gt;, boost::concepts::requirement&lt;boost::concepts::failed************ boost::SinglePassRangeConcept&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt;::************&gt; &gt;’
  boost_1_53_0/boost/concept/detail/general.hpp:50:8:   instantiated from ‘boost::concepts::requirement_&lt;void (*)(boost::SinglePassRangeConcept&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt;)&gt;’
  boost_1_53_0/boost/range/algorithm/copy.hpp:33:1:   instantiated from ‘OutputIterator boost::range::copy(const SinglePassRange&amp;, OutputIterator) [with SinglePassRange = boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)()), OutputIterator = std::_List_iterator&lt;boost::filesystem::directory_entry&gt;]’
  ~/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&lt;false, boost::range_const_iterator&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt;, boost::range_mutable_iterator&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt; &gt;::f_ {aka struct boost::range_mutable_iterator&lt;boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)())&gt;}’
  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&amp;, OutputIterator) [with SinglePassRange = boost::iterator_range&lt;boost::filesystem::directory_iterator&gt;(boost::filesystem::directory_iterator, boost::filesystem::directory_iterator (*)()), OutputIterator = std::_List_iterator&lt;boost::filesystem::directory_entry&gt;]’:
  ~/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&lt;boost::filesystem::directory_iterator&gt; (&amp;)(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&lt;class T&gt; typename boost::range_iterator::type boost::range_adl_barrier::begin(T&amp;)
  boost_1_53_0/boost/range/begin.hpp:112:61: note: template&lt;class T&gt; typename boost::range_iterator&lt;const T&gt;::type boost::range_adl_barrier::begin(const T&amp;)
  boost_1_53_0/boost/range/algorithm/copy.hpp:34:59: error: no matching function for call to ‘end(boost::iterator_range&lt;boost::filesystem::directory_iterator&gt; (&amp;)(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&lt;class T&gt; typename boost::range_iterator::type boost::range_adl_barrier::end(T&amp;)
  boost_1_53_0/boost/range/end.hpp:106:61: note: template&lt;class T&gt; typename boost::range_iterator&lt;const T&gt;::type boost::range_adl_barrier::end(const T&amp;)
  boost_1_53_0/boost/range/algorithm/copy.hpp:35:1: warning: control reaches end of non-void function [-Wreturn-type]
  </code></pre>
  
  <p>I wasn't really able to filter out the relevant lines, but I think that it is possible to filter files using range adaptors (I don't just want to copy the range, after all). My impression is that somewhere along the way <code>datFiles.begin()</code> doesn't satisfy a concept needed by the copy algorithm.</p>
  
  <hr>
  
  <h2>Some of my solutions</h2>
  
  <p>Here are some of the solutions (including filtering) I came up with, based on Jonathan's answer.</p>
  
  <p>Using a global predicate function <code>bool isDatFile(const path&amp; p)</code>:</p>
  
  <pre><code>std::list&lt;directory_entry&gt; datFiles;
  boost::copy(rng | boost::adaptors::filtered(isDatFile), std::back_inserter(datFiles));
  </code></pre>
  
  <p>I preferred a local function, though, so I tried that. This one is just checking if the directory entry is a regular file, the static cast was needed because <code>is_regular_file</code> is overloaded:</p>
  
  <pre><code>std::list&lt;directory_entry&gt; datFiles;
  boost::copy(rng
              | boost::adaptors::filtered(static_cast&lt;bool (*)(const path&amp;)&gt;(&amp;is_regular_file)),
              std::back_inserter(datFiles));
  </code></pre>
  
  <p>Checking for the right extension in the range adaptor as well was a bit hard, so I added a local function:</p>
  
  <pre><code>std::list&lt;directory_entry&gt; datFiles;
  bool BOOST_LOCAL_FUNCTION(const path&amp; p)
  {
    return (is_regular_file(p) &amp;&amp; (extension(p) == string(".dat")));
  } BOOST_LOCAL_FUNCTION_NAME(isDatFile_l)
  boost::copy(rng
              | boost::adaptors::filtered(isDatFile_l),
              std::back_inserter(datFiles));
  </code></pre>
  
  <p>And finally the "one-liner" using bind:</p>
  
  <pre><code>std::list&lt;directory_entry&gt; datFiles;
  boost::copy(rng
              | boost::adaptors::filtered(static_cast&lt;bool (*)(const path&amp;)&gt;(&amp;is_regular_file))
              | boost::adaptors::filtered(boost::bind(std::equal_to&lt;path&gt;(), boost::bind(extension, _1), path(".dat"))),
              std::back_inserter(datFiles));
  </code></pre>