如何隐藏range-v3的复杂范围类型?

时间:2018-12-07 15:06:55

标签: c++ c++14 c++17 range-v3

我需要一个带有使用range-v3库返回某种范围的方法的类。 为了实现这样的类,我可以在该类的定义中正确地编写它。例如:

#include <iostream>
#include <set>
#include <range/v3/view/transform.hpp>

class Alpha {
public:
  int x;
};

class Beta : public Alpha {};

class Foo {
public:
  std::set<Alpha*> s;

  auto r() { return s | ranges::v3::view::transform([](Alpha* a) { return static_cast<Beta*>(a); }) }
};

但是,在我的实际情况下,Foo::r函数非常复杂,我想隐藏其实现。 特别是,该实现利用了一些其他的库,否则在声明类Foo时不需要包含这些库。

但是,当Foo::r的定义与其声明分开时,必须明确指定其返回类型。 decltype comes with some help

头文件:

class Foo {
public:
  std::set<Alpha*> s;

  using RangeReturn = decltype(std::declval<std::set<Alpha*>&>() | ranges::v3::view::transform(std::function<Beta*(Alpha*)>()));
  RangeReturn r();
};

实施,cpp文件:

#include "Foo.h"

Foo::RangeReturn Foo::r() {
    return s | ranges::v3::view::transform(std::function<Beta*(Alpha*)>{
      [](Alpha* a) { return static_cast<Beta*>(a); }
      });
}

这立即完成了隐藏Foo::r的实际实现的工作。 但是,返回值的类型仍然有效地“泄漏”了有关如何构造范围的信息。 更糟糕的是,我现在不得不在范围管道中显式使用std::function对象。

但是,返回范围的用户是否真的需要所有信息? Foo::r的所有用户都关心它是某种可迭代的。它具有:

  • begin()为范围的开头提供迭代器
  • end()提供一些迭代器或哨兵
  • 迭代器可以增加,以在范围内进行迭代
  • 可以取消引用迭代器,提供某种类型的T(在示例情况下为Beta*)。

用户不在乎是否存在转换视图,也不在乎转换,过滤器等的数量。

所以,我的问题是-是否可以隐藏所有信息?我希望能够编写如下内容:

在标题中:

class Foo {
public:
  std::set<Alpha*> s;

  Iterable<Beta*> r();
};

在cpp文件中:

#include "Foo.h"

Iterable<Beta*> Foo::r() {
    return s | ranges::v3::view::transform([](Alpha* a) { return static_cast<Beta*>(a); });
}

我可以接受这样一个事实,即所产生的Iterable类型可能包含由于隐藏过程而无法内联的真实函数调用。 链接时间优化以后可能会也可能无法优化。

不幸的是,据我所知,Iterable只是一个概念,并不是库中的单独类型。

1 个答案:

答案 0 :(得分:3)

您要查找的r()的返回类型为ranges::v3::any_view<Beta*>

请注意,它应用了类型擦除,这意味着某些运行时性能损失可能会很大。相关讨论:poor performance of type-erased views

实时演示:https://wandbox.org/permlink/JylKIHD0NaQsRXdB