否定增强范围过滤适配器

时间:2013-02-08 09:28:47

标签: c++ boost lambda boost-range

是否可以/可实现否定升压滤波适配器,例如

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

而不是在lambda表达式中进行否定?

动机:我使用过滤和lambda函数工作很多,但是当我多次使用过滤器时,我通常会将其重构为自定义过滤器,例如

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

现在,当我需要否定时,我正在为它们构建自定义过滤器,例如

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

但我觉得能够否定过滤器更好,例如

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

2 个答案:

答案 0 :(得分:7)

以下是我在短时间内提出的建议:

#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';
    }
}

liveworkspace.org

上查看

请注意,它当前处理function pointerstd::function<...>形式的谓词,但尚未处理裸lambdas(在GCC 4.7.2上)

答案 1 :(得分:0)

这并不能完全回答问题,因为它不会否​​定过滤器,而只会否定谓词。我仍然发布此消息,因为搜索解决方案将这个问题作为第一个结果。

other answer相比,它的优点是我们不需要向namespace boost::range_detail添加自定义代码。

C ++ 17解决方案

函数std::not_fn可用于创建否定谓词。

#include <boost/range/adaptors.hpp>
#include <functional>
#include <iostream>

struct is_even
{
    bool operator()( int x ) const { return x % 2 == 0; }
};

int main()
{
    using namespace boost::adaptors;
    int const v[] = { 1, 2, 3, 4 };

    for( auto i : v | filtered( std::not_fn( is_even{} ) ) )
    {
        std::cout << i << ' ';
    }
}

Live Demo

C ++ 11,C ++ 14解决方案

函数std::not1可用于创建否定谓词。它还有一个附加要求,即谓词必须定义成员类型argument_type,该成员类型与谓词operator()参数具有相同的类型。

#include <boost/range/adaptors.hpp>
#include <functional>
#include <iostream>

struct is_even
{
    using argument_type = int;
    bool operator()( int x ) const { return x % 2 == 0; }
};

int main()
{
    using namespace boost::adaptors;
    int const v[] = { 1, 2, 3, 4 };

    for( auto i : v | filtered( std::not1( is_even{} ) ) )
    {
        std::cout << i << ' ';
    }
}

Live Demo