我需要一个带有使用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
只是一个概念,并不是库中的单独类型。
答案 0 :(得分:3)
您要查找的r()
的返回类型为ranges::v3::any_view<Beta*>
。
请注意,它应用了类型擦除,这意味着某些运行时性能损失可能会很大。相关讨论:poor performance of type-erased views。