10

使用有什么好处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 的场景。也许我错过了一些东西。

4

2 回答 2

17

这种技术称为类型擦除。有一篇完整的文章描述了以下示例的优缺点any_iteratorOn 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)

您必须向用户提供源代码(或至少在某处进行显式实例化)。

此外,在第一种情况下,display_integers只会编译一次,但在第二种情况下,它将针对传递范围的每种类型进行编译。

另外,你可能有某个地方

integer_range rng;

并且在您的一生中rng可以为其分配不同类型的范围:

vector<int> v;
list<int> l;
integer_range rng;
rng = v;
rng = l;

类型擦除的最大缺点是它的运行时间成本;所有操作都是虚拟的,不能内联(容易)。


PS 类型擦除的另一个著名例子是std::function

于 2013-03-15T21:34:30.260 回答
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::functionclang 3.2 通过直接传递 lambda 来工作

很难知道这个函数返回了什么。此外,lambda 和 decltype不能一起工作,因此我们无法decltype在仅传递 lambda 时推断使用的类型。一种解决方案是boost::any_range像您的示例中那样使用(另一种解决方法是使用Evgeny Panasyuk在评论中std::function指出的):

integer_range make_range(std::vector<int> v)
{
     return v | filter([](int x){ return x % 2 == 0;})
        | transform([](int x){ return x * 2;});
}

使用gcc 的工作示例std::function

使用 clang直接传递 lambda的工作示例。

于 2013-03-15T21:42:47.127 回答