我需要一个具有使用 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()
给一些迭代器或哨兵- 迭代器可以递增,以迭代范围
- 可以取消引用迭代器,给出某种类型
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
只是一个概念,而不是库中的一个单独类型。