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

How to hide the complex range type of a range-v3?

我需要一个 class 的方法 return 使用 range-v3 库的某种范围。 为了实现这样一个 class 我可以把它的一切都写在那个 class 的定义中。例如:

#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 函数非常复杂,我想隐藏它的实现。 特别是,该实现使用了一些额外的库,否则在声明 class Foo 时不需要包含这些库。

但是,当 Foo::r 的定义与其声明分开时,必须明确指定其 return 类型。 :

Header 个文件:

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 的实际实现。 但是,return 值的类型仍然有效地 "leaks" 有关如何构建范围的信息。 更糟糕的是,我现在被迫在范围管道中显式使用 std::function object。

但是 returned 范围内的用户真的需要所有信息吗? Foo::r 的所有用户都关心它是某种可迭代对象。它有:

用户不关心有没有转换视图,也不关心转换、过滤器等的数量。

那么,我的问题是 -- 有没有办法隐藏所有这些信息?我希望能够写出这样的东西:

在header:

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 类型可能包含由于隐藏过程而无法内联的真实函数调用。 link-time 优化以后可能会也可能不会对其进行优化。

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

您要找的r()的return类型是ranges::v3::any_view<Beta*>

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

现场演示:https://wandbox.org/permlink/JylKIHD0NaQsRXdB