使用boost::any_range
有什么好处?
这是一个例子:
typedef boost::any_range<
int
, boost::forward_traversal_tag
, int
, std::ptrdiff_t
> integer_range;
void display_integers(const integer_range& rng)
{
boost::copy(rng,
std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
}
int main(){
std::vector<int> input{ ... };
std::list<int> input2{ ... };
display_integers(input);
display_integers(input2);
}
但是使用模板参数可以实现更高效的相同功能,该参数满足ForwardRange概念:
template <class ForwardRange>
void display_integers(const ForwardRange& rng)
{
boost::copy(rng,
std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
}
所以我正在寻找值得使用any_range的场景。也许我错过了什么。
答案 0 :(得分:17)
这种技术称为Type Erasure。有一篇完整的文章描述了any_iterator
:On the Tension Between Object-Oriented and Generic Programming in C++示例的优缺点。
可以隐藏(在单独的文件/库中)
的实现/定义void display_integers(const integer_range& rng)
但是在
的情况下template <class ForwardRange>
void display_integers(const ForwardRange& rng)
您必须向用户提供源代码(或至少在某处制作explicit instantiations)。
此外,在第一种情况下,display_integers
将只编译一次,但在第二种情况下,它将针对传递范围的每种类型进行编译。
另外,你可能有某个地方
integer_range rng;
并且在rng
的生命周期内,您可以指定different types to it的范围:
vector<int> v;
list<int> l;
integer_range rng;
rng = v;
rng = l;
类型擦除的最大缺点是其运行时成本;所有操作都是虚拟的,无法内联(轻松)。
P.S。另一个着名的类型擦除示例是std::function
答案 1 :(得分:10)
boost::any_range
可用于从函数返回范围。想象一下以下示例:
auto make_range(std::vector<int> v) -> decltype(???)
{
return v | filter([](int x){ return x % 2 == 0;})
| transform([](int x){ return x * 2;});
}
*:gcc不编译上面的内容而不将其包装在std::function
中,hower clang 3.2的工作方式是直接传递lambda
很难知道从这个函数返回什么。此外,lambda and decltype不能一起工作,因此我们无法在仅传递lambda时使用decltype
来推断类型。一种解决方案是使用boost::any_range
,例如示例中的std::function
(另一种解决方法是使用评论中Evgeny Panasyuk指出的integer_range make_range(std::vector<int> v)
{
return v | filter([](int x){ return x % 2 == 0;})
| transform([](int x){ return x * 2;});
}
):
std::function
使用{{1}}的工作示例with gcc。
工作示例with clang直接传递lambdas。