代码之家  ›  专栏  ›  技术社区  ›  Aleph0

如何使用boost范围在函数中封装自定义迭代器

  •  4
  • Aleph0  · 技术社区  · 6 年前

    最近我在用 boost-range 在满足特定条件的元素上创建范围。在所有情况下,我一直在使用相同类型的过滤范围,因此我试图将此行为封装在外部函数中。

    这就是我的问题开始的地方。考虑下面的例子。

    #include <boost/range/adaptor/filtered.hpp>
    #include <iostream>
    #include <vector>
    
    auto myFilter = [](const std::vector<int>& v, int r) {
        return v | boost::adaptors::filtered([&r](auto v) { return v%r == 0; });
    };
    
    int main(int argc, const char* argv[])
    {
        using namespace boost::adaptors;
    
        std::vector<int> input{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    
        for (auto& element : input | filtered([](auto v) {return v % 2 == 0; } ))
        {
            std::cout << "Element = " << element << std::endl;
        }
        std::cout << std::endl;
        for (auto& element : myFilter(input,4))
        {
            std::cout << "Element = " << element << std::endl;
        }
        return 0;
    }
    

    第一个for循环的行为与预期的打印4和8相同。不过,第二个for循环只打印4个。为什么?

    我的第二个想法是实现一个 begin() end() 功能。这应该是一个范围对象的薄包装。

    这就是解决方案,在修改了范围迭代器的类型之后。

    struct MyFilter {
        MyFilter(const std::vector<int>& c, int r) : c(c), r(r), f([&r](auto v) { return v%r == 0; }) {
        }
    
        boost::range_detail::filtered_range<std::function<bool(int)>, std::vector<int>>::iterator begin() {
            return rng.begin();
        }
    
        boost::range_detail::filtered_range<std::function<bool(int)>, std::vector<int>>::iterator end() {
            return rng.end();
        }
    
        std::vector<int> c;
        int r;
        std::function<bool(int)> f;
        boost::range_detail::filtered_range < std::function<bool(int)>, std::vector<int>> rng=c | boost::adaptors::filtered(f);
     };
    

    用法应该类似于:

        for (auto& element : MyFilter(input, 4)) {
            std::cout << "Element = " << element << std::endl;
        }
    

    不幸的是,它只打印了4个。哪个对我来说很奇怪??

    现在,我自己解决了。我必须删除lambda函数中的“&”才能使其工作!

    1 回复  |  直到 6 年前
        1
  •  3
  •   Maxim Egorushkin    6 年前

    在:

    auto myFilter = [](const std::vector<int>& v, int r) {
        return v | boost::adaptors::filtered([&r](auto v) { return v%r == 0; });
    };
    

    它返回另一个范围适配器 r 被引用捕获的将成为悬挂引用。修复它捕获 R 按值:

    auto myFilter = [](const std::vector<int>& v, int r) {
        return v | boost::adaptors::filtered([r](auto v) { return v%r == 0; });
    };                                        ^
                                              +--- capture by value