Cyg*_*sX1 5 c++ c++14 range-v3 c++17
我需要一个带有使用 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); }) }
};
Run Code Online (Sandbox Code Playgroud)
但是,在我的真实案例中,该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();
};
Run Code Online (Sandbox Code Playgroud)
实现,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); }
});
}
Run Code Online (Sandbox Code Playgroud)
这可以立即完成隐藏Foo::r. 但是,返回值的类型仍然有效地“泄漏”了有关如何构造范围的信息。更糟糕的是,我现在被迫std::function在范围管道中明确使用一个对象。
但是,返回范围的用户真的需要这些信息吗?Foo::r关心的所有用户都是它是某种可迭代的。它有:
begin() 给范围的开头提供一个迭代器end() 提供一些迭代器或哨兵T(Beta*在示例中)。用户不关心是否有转换视图,也不关心转换、过滤器和诸如此类的数量。
所以,我的问题是——有没有办法隐藏所有这些信息?我希望能够写出这样的东西:
在标题中:
class Foo {
public:
std::set<Alpha*> s;
Iterable<Beta*> r();
};
Run Code Online (Sandbox Code Playgroud)
在 cpp 文件中:
#include "Foo.h"
Iterable<Beta*> Foo::r() {
return s | ranges::v3::view::transform([](Alpha* a) { return static_cast<Beta*>(a); });
}
Run Code Online (Sandbox Code Playgroud)
我可以接受这样一个事实,即生成的Iterable类型可能包含由于隐藏过程而无法内联的真实函数调用。链接时优化以后可能会也可能不会对其进行优化。
不幸的是,据我所知,这Iterable只是一个概念,而不是库中的一个单独类型。
r()您正在寻找的返回类型是ranges::v3::any_view<Beta*>.
请注意,它应用了类型擦除,这意味着可能会产生一些显着的运行时性能损失。相关讨论:类型擦除视图的性能不佳。
现场演示: https: //wandbox.org/permlink/JylKIHD0NaQsRXdB
| 归档时间: |
|
| 查看次数: |
453 次 |
| 最近记录: |