我有一个带有谓词的类,例如,
Object::isValid()
。我只需要迭代有效的对象,所以我使用范围/视图:
struct Object {
bool isValid() const;
// ...
};
// Usage:
std::vector<Object> objects = getObjects();
for (const auto &obj : objects |
std::ranges::view::filter(
[](const Object &obj) {
return obj.isValid();
})
) {
// Use obj that is of type `const Object &`
}
到目前为止一切顺利。现在我需要分离有效对象视图的生产者和消费者:
auto getValidObjectsView() {
return objects |
std::ranges::views::filter(
[](const Object &obj) {
return obj.isValid();
}
);
}
void consumeValidObjects(auto &&validObjectsView) {
for (const auto &obj : validObjectsView) {
// Use `obj`
}
}
consumeValidObjects(getValidObjectsView());
这也有效,但现在我需要将函数的实现隐藏到单独的翻译单元中,以暴露标头中的签名。因此我不能再使用
auto
了。
问题是
getValidObjectsView()
函数的返回类型取决于 std::ranges::views::filter
以及该函数内部使用的 lambda,所以我不能简单地在函数签名中使用这种类型:
using ObjectsIterable = // whatever compiler reports as decltype<getValidObjectsView()> from the previous snippet
ObjectsIterable getValidObjectsView();
void consumeValidObjects(const ObjectsIterable &)
consumeValidObjects(getValidObjectsView());
我的问题是如何定义一个代理类型
ObjectsIterable
,它会删除生产者返回的实际底层类型,类似这样:
using ObjectsIterable = std::ranges::view::one_size_fits_all_view<Object>;
您可以通过将 lambda 转换为函数指针来类型擦除 lambda,而不是类型擦除返回的视图,这允许将函数的返回类型声明为
std::ranges::filter_view<
std::ranges::ref_view<std::vector<Object>>,
bool (*)(const Object&)
>
getValidObjectsView() {
return objects |
std::ranges::views::filter(
+[](const Object &obj) {
return obj.isValid();
}
);
}