1

我有一个多态接口

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()和 by返回的类型some_range()不同,例如一个可以是 a filtered counting range,另一个可以是 a transformed filtered counting range。对于接口,我需要一种Range类型。

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

有没有替代品any_range和复制品?

4

2 回答 2

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

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

于 2013-07-02T17:56:59.090 回答
0

如果只有已知的 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;
}
于 2013-07-08T23:04:48.057 回答