我有一个多态接口
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
和复制的替代方案?
有点,但不是真的。
当您不知道数据的存储方式时,您希望按顺序访问数据。你有三个选择:
- 将数据复制到具有已知格式的容器中("返回向量"选项)
- 使用编译时多态性来选择正确的访问方法(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;
};
当然,只有当你使用范围的方式非常有限时,这才有效。
如果只有已知的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;
}