2013-06-25 81 views
1

我有一個多態接口在C++接口使用Boost.Range

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有沒有其他的選擇和複製?

回答

1

有點,但不是真的。

如果您不知道如何存儲數據,您希望順序訪問數據。您有三種選擇:

  • 將數據複製到已知格式的容器中(「返回矢量」選項)。
  • 使用編譯時多態來選擇正確的訪問方法(std算法執行此操作的方式,由於您使用的是接口而不可行)。
  • 使用運行時多態性來選擇正確的訪問方法。

所以第二個是不可能的,因爲你想要使用接口的約束。第一個和第三個都有開銷。

做第三件事的明顯方法是any_range。但這不是唯一的方法,取決於你想要做什麼。 any_range的問題在於,在簡單的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; 
}; 

當然,這隻能作爲只要您使用範圍的方式非常有限。

+0

感謝您的回答,在界面包裹算法是一種可能性,我沒有這樣的考慮。可以肯定的是,在「for_each」算法排序之後,binary_search,然後......接口中成員函數的爆炸式增長。也許這不會發生在我的應用程序中,所以你的建議可能是最好的解決方案(至少與any_range結合)。我會睡覺,非常感謝這個想法! – gnzlbg

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