【问题标题】:Using Boost.Range in C++ interfaces在 C++ 接口中使用 Boost.Range
【发布时间】:2013-06-25 12:58:53
【问题描述】:

我有一个多态接口

struct Interface {
  Interface(SomeType& other)
  : range([=](){ return other.my_range(); }), /*...*/ {}
  Interface(SomeOtherType& other)
  : range([=](){ return other.some_range(); }), /*...*/ {}

  const std::function<Range(void)> range;
  /// ...
};

两个范围内的元素属于同一类型(例如int),但my_range()some_range() 返回的类型不同,例如一个可以是filtered counting range,另一个可以是transformed filtered counting range。对于界面,我需要一个 Range 类型。

我尝试过使用boost::any_range,但性能明显更差。我想避免将范围元素复制到 vector 并返回向量。

any_range 和复制有什么替代方法吗?

【问题讨论】:

    标签: c++ interface polymorphism boost-range


    【解决方案1】:

    有点,但不是真的。

    当您不知道数据的存储方式时,您希望按顺序访问数据。您有三个选择:

    • 将数据复制到已知格式的容器中(“返回向量”选项)。
    • 使用编译时多态性来选择正确的访问方法(std 算法这样做的方式,由于您使用了接口,所以不可能)。
    • 使用运行时多态性选择正确的访问方法。

    因此,由于您要使用接口的限制,第二个是不可能的。第一个和第三个都有开销。

    做第三件事的明显方式是any_range。但这不是唯一的方法,取决于你想做什么。 any_range 的问题在于,在一个简单的 for-each 循环中,每个元素都有三个虚拟调用:递增、比较和取消引用。

    只要您想做的只是简单的 for-each 迭代,您就可以通过在接口级别实现循环来减少一次虚拟调用的开销:

    struct Interface {
        Interface(SomeType& other)
        : traverse([=](std::function<void(int)> body) {
          for (int i : other.my_range()) body(i);
        }) {}
    
        const std::function<void (std::function<void(int)>)> traverse;
    };
    

    当然,这只有在您使用范围的方式非常有限时才有效。

    【讨论】:

    • 感谢您的回答,在界面中包装算法是我没有考虑过的一种可能性。缺点是在“for_each”算法之后是排序、二进制搜索,然后......接口中成员函数的爆炸式增长。也许这不会发生在我的应用程序中,所以您提出的可能是最好的解决方案(至少与 any_range 结合使用)。我会睡在上面,非常感谢这个想法!
    【解决方案2】:

    如果只有 2 种已知类型(或固定数量的类型),则可以选择 Boost.Variant。这是示例用法:

    #include <boost/variant.hpp>
    #include <functional>
    
    struct SomeType
    {
        typedef int range_t;
        range_t my_range() const { return 1; }
    };
    
    struct SomeOtherType
    {
        typedef double range_t;
        range_t some_range() const { return 3.14; }
    };
    
    typedef std::function<SomeType::range_t (void)> SomeTypeRange;
    typedef std::function<SomeOtherType::range_t (void)> SomeOtherTypeRange;
    typedef boost::variant<SomeTypeRange, SomeOtherTypeRange> Range;
    
    struct Interface
    {
      Interface(const SomeType& other)
      : range( SomeTypeRange([=](){ return other.my_range(); }) ) {}
    
      Interface(const SomeOtherType& other)
      : range( SomeOtherTypeRange([=](){ return other.some_range(); }) ) {}
    
      Range range;
    };
    
    struct print_me_visitor : public boost::static_visitor<void>
    {
    public:
        void operator()( const SomeTypeRange& i_st ) const
        {
            std::cout << "SomeTypeRange: " << i_st() << std::endl;
        }
    
        void operator()( const SomeOtherTypeRange& i_sot ) const
        {
            std::cout << "SomeOtherTypeRange: " << i_sot() << std::endl;
        }
    };
    
    int main()
    {
        SomeType st;
        SomeOtherType sot;
        Interface i1( st );
        Interface i2( sot );
    
        boost::apply_visitor( print_me_visitor(), i1.range );
        boost::apply_visitor( print_me_visitor(), i2.range );
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-21
      • 2017-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-29
      相关资源
      最近更新 更多