5

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

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
4

2 回答 2

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 pointerand std::function<...>,但尚未处理裸 lambdas(在 GCC 4.7.2 上)

于 2013-02-08T11:12:30.687 回答
1

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

其他答案相比,这具有我们不需要添加自定义代码的优势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 << ' ';
    }
}

现场演示

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

现场演示

于 2019-01-11T12:06:16.543 回答