Search code examples
boostboost-filesystemboost-range

Compilation issue with boost range copy of filesystem path


The following code fails to compile with 1.58 while it was compiling with 1.46. I guess it's a type conversion issue, but I can't make it right.

my code

#include <boost/filesystem.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <vector>

using namespace boost;
using namespace filesystem;
using namespace adaptors;

int main(int argc, char ** argv)
{
    recursive_directory_iterator beg = recursive_directory_iterator(".");
    recursive_directory_iterator end = recursive_directory_iterator();

    iterator_range<recursive_directory_iterator> files = 
        make_iterator_range(beg, end);

    std::function<bool (path const & path)> fileFilter = 
        [](path const & path) -> bool {
        return is_regular_file(path);
    };

    std::vector<path> paths;
    copy(files | filtered(fileFilter), std::back_inserter(paths));

    // works:
    //copy(files, std::back_inserter(paths));

    // also works:
    //for(recursive_directory_iterator it = beg; it != end; ++it){
    //    if(fileFilter(*it)){
    //        paths.push_back(*it);
    //    }
    //}
}

Error message (VS2010)

Error 1 error C2664: 'boost::filesystem::recursive_directory_iterator::recursive_directory_iterator(const boost::filesystem::path &,boost::filesystem::symlink_option::enum_type)' : cannot convert parameter 1 from 'boost::iterators::detail::postfix_increment_proxy' to 'const boost::filesystem::path &' [...]\boost\1.58.0_32\include\boost-1_58\boost\range\concepts.hpp 201 1 [...]

Can anyone help ?

Edit

Filed as https://svn.boost.org/trac/boost/ticket/11228.


Solution

  • This seems to be a bug introduced somewhere since Boost 1.55. Using boost 1.55 this compiles ok.

    It could be this bug: https://svn.boost.org/trac/boost/ticket/10989

    boost_1_57_0/boost/concept_check.hpp|210 col 13| error: conversion from ‘boost::iterators::single_pass_traversal_tag’ to non-scalar type ‘boost::iterators::forward_traversal_tag’ requested

    The filtered adaptor requires the input to be forward_traversal tag. But recursive_directory_iterator only promises single_pass_traversal tag:

            BOOST_RANGE_CONCEPT_ASSERT((
                Convertible<
                    BOOST_DEDUCED_TYPENAME ForwardIteratorConcept::traversal_category,
                    forward_traversal_tag
                >));
    

    WORKAROUND

    You can disable concept checks for now: -DBOOST_RANGE_ENABLE_CONCEPT_ASSERT=0:

    Live On Coliru

    #include <boost/filesystem.hpp>
    #include <boost/range.hpp>
    #include <boost/range/algorithm.hpp>
    #include <boost/range/adaptors.hpp>
    #include <vector>
    #include <iostream>
    
    namespace fs = boost::filesystem;
    using namespace boost::adaptors;
    
    int main() {
        fs::recursive_directory_iterator beg("."), end;
    
        auto fileFilter = [](fs::path const & path) { return is_regular_file(path); };
    
        std::vector<fs::path> paths;
        copy(boost::make_iterator_range(beg, end) | filtered(fileFilter), std::back_inserter(paths));
    
        for(auto& p : paths)
            std::cout << p << "\n";
    }
    

    Prints

    "./main.cpp"
    "./a.out"