c++boostlambdaboost-range

Negate boost range filtered adaptor


Is it possible/achievable to negate a boost filtered adaptor, e.g.

std::vector<int> v = {1, 2, 3, 4, 5};
for(auto i : v | !filtered(is_even))
    std::cout << i << std::endl; // prints 1,3,5

instead of doing the negation inside the lambda expression?

Motivation: I work a lot with filtered and lambda functions, however when I use a filter more than once I usually refactor it into a custom filter, e.g.

for(auto i : v | even) // note: my filters are more complex than even.
    std::cout << i << std::endl; // prints 2,4

Right now when I need the negation I am building a custom filter for them, e.g.

for(auto i : v | not_even)
    std::cout << i << std::endl; // prints 1,2,3

but I would find it nicer to just be able to negate a filter, e.g.

for(auto i : v | !even)
    std::cout << i << std::endl; // prints 1,2,3

Solution

  • Here's what I came up with on short notice:

    #include <boost/range/adaptors.hpp>
    #include <boost/functional.hpp>
    #include <iostream>
    
    namespace boost { 
        namespace range_detail { 
    
            template <typename T>
                auto operator!(filter_holder<T> const& f) -> decltype(adaptors::filtered(boost::not1(f.val)))
                {
                    return adaptors::filtered(boost::not1(f.val));
                }
        }
    }
    
    int main()
    {
        using namespace boost::adaptors;
        int const v[] = { 1, 2, 3, 4 };
    
        std::function<bool(int)> ll = [](int i){return 0 == (i%2);}; // WORKS
        // bool(*ll)(int) = [](int i){return 0 == (i%2);};           // WORKS
        // auto ll = [](int i){return 0 == (i%2);};                  // not yet
    
        auto even = filtered(ll);
    
        for (auto i : v | !even)
        {
            std::cout << i << '\n';
        }
    }
    

    See it live on liveworkspace.org

    Note that it currently handles predicates of the form function pointer and std::function<...>, but not naked lambdas yet (on GCC 4.7.2)