首页 > 解决方案 > 类型不可知的抽象以使用相同的运行时接口处理正向和反向迭代器和范围?

问题描述

通过设计正向和反向迭代器和范围是根本不同的类型。这在它允许的编译时优化中很好。有时最好将类型差异隐藏在允许将它们传递到相同运行时接口的抽象后面。

是否有任何适配器booststl使这变得容易?(理想但不严格的 C++11)

以下代码显示了已知/预期的失败和所需的假设:

    #include <boost/range.hpp>
    #include <vector>
      
    using Ints = std::vector<int>;
      
    void real(boost::iterator_range<Ints::iterator> range){}
    void fake(boost::agnostic_range<Ints::iterator> range){} // imaginary desired
      
    int main()
    {
        auto ints = Ints{1,2,3,4,5};
      
        real(boost::make_iterator_range(ints.begin(),  ints.end())); 
        real(boost::make_iterator_range(ints.rbegin(), ints.rend())); // Error
        fake(boost::make_agnsotic_range(ints.begin(),  ints.end()));  // imaginary
        fake(boost::make_agnsotic_range(ints.rbegin(), ints.rend())); // imaginary
        return 0;
    }

标签: c++boostiteratorrange

解决方案


是的!Boost::any_rangetype 擦除迭代对象类型并仅公开输出类型和迭代器访问类型。

请注意,此处的类型擦除需要通过虚函数调用以取消引用迭代器,因此存在性能成本,但只要在循环内执行非平凡操作,此成本可能无关紧要。

BUG 警告: 在 ~ ish 到发布(2020-08)boost::range之间有一个大错误,这将导致访问被破坏的项目,这将导致 UB(未定义的行为/可能崩溃)解决此问题的方法存在于下面的代码中通过模板参数显式传递所谓的引用类型,这会导致一些内部机制避免出错。1.551.74 any_rangeconst

    #include <boost/range/adaptor/type_erased.hpp>
    #include <boost/range/adaptor/reversed.hpp>
    #include <boost/range/any_range.hpp>
    #include <vector>
    #include <list>
    #include <iostream>

    // note const int bug workaround
    using GenericBiDirIntRange = 
        boost::any_range<int, boost::bidirectional_traversal_tag, const int>; 

    void possible(GenericBiDirIntRange const &inputRange) {
        for(auto item: inputRange)
            std::cout << item << "\n";
    }
           
    // note const int bug workaround                                                           
    using type_erased_bi =
        boost::adaptors::type_erased<int, boost::bidirectional_traversal_tag, const int>;
    using reversed = boost::adaptors::reversed;
                                                                                                                                    
    auto main() -> int {                                                                                                            
                                                                                                                                    
        auto intVec = std::vector<int>{1, 2, 3, 4};                                                                                   
        auto intList = std::list<int>{1, 2, 3, 4};                                                                                    
                                                                                                                                    
        possible(intVec | type_erased_bi());                                                                                          
        possible(intList | reversed | type_erased_bi());                                                                                         
                                                                                                                                    
        return 0;
    }



推荐阅读