6

我需要一个具有使用 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附带一些帮助

头文件:

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()给一些迭代器或哨兵
  • 迭代器可以递增,以迭代范围
  • 可以取消引用迭代器,给出某种类型TBeta*在示例中)。

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

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

在标题中:

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只是一个概念,而不是库中的一个单独类型。

4

1 回答 1

4

r()您正在寻找的返回类型是ranges::v3::any_view<Beta*>.

请注意,它应用了类型擦除,这意味着一些运行时性能损失可能很重要。相关讨论:类型擦除视图的性能不佳

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

于 2018-12-07T15:45:38.260 回答