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

Type agnostic abstraction to handle forward and reverse iterators and ranges using the same runtime interface?

本文关键字:处理 迭代器 范围 接口 运行时 抽象 不可知 类型      更新时间:2023-10-16

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

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

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

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

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

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