c++ - std::vector 的协变包装器

标签 c++ covariance

我想要 std::vector 的协变包装器.我的想法是做这样的事情:

  • 创建抽象基类BaseVector<B>谁的beginend方法只是转发给纯虚函数。
  • 创建一个具体的派生类DerivedVector<B, D>包裹着 std::vector<D> .它的beginend方法将隐藏基类的方法,并且它将实现基类转发到的虚拟方法。

这样,如果你有一个指向 BaseVector 的指针你可以迭代基类实例,如果你有一个 DerivedVector您可以迭代派生类实例的指针。

(编辑:显然 BaseVector 不一定支持插入,因为它不知道它包含的对象的类型。也许这意味着“vector ”不是最好的名字为此;我愿意接受建议。谢谢@CygnusX1。)

对于 DerivedVector begin 和 end 方法类可以直接转发到 std::vector的。

问题:我如何实现 BaseVector 的方法? beginend转发?我是否必须编写自己的迭代器类来包装 std::vector迭代器?

或者:是否有更好或更简单的方法来做到这一点?

A DerivedVector<B, D>实例需要通过 BaseVector<B> 可用知道 B 的代码中的指针但不是 D ,并且它需要具有与仅持有派生类 vector 相同的性能(如果调用代码知道派生类)

示例用例:

一个图书馆提供了一个BaseWidget类和一个BaseWidgetPool类,用户从中派生。由于图书馆的性质,在任何给定的程序中都会有一个 DerivedWidget类,但是对于使用该库的每个程序,该类都会有所不同。

BaseWidgetPool类包括迭代池中所有小部件并利用其 BaseWidget 的方法功能。但是每个程序的 DerivedWidgetPool很可能想要使用 DerivedWidget其内容的功能。

(我知道我也可以通过制作一个通用的 WidgetPool<T> 类来处理这个问题,但我宁愿将 T 封装到实际使用它的代码部分。)

最佳答案

有了范围,这就不是问题了。它具有多态范围所需的所有 API:

#include <range/v3/all.hpp>

namespace rv = ranges::view;

int main() {
    std::vector<Derived> derived_container;

    // ... fill it

    ranges::any_view<Base*> base_view =
        rv::all(derived_container) | rv::transform([](auto& e) -> Base* { return &e; });

    // do stuff with `base_view`
}

那么只要 derived_container 存在,您就可以使用 base_view

我使用了 any_view 这样范围就被类型删除了。您可以在不需要模板化函数的情况下传递它,也可以在虚函数中传递它。

如果您不能使用标准范围或范围 v3,我会创建一个类似的包装器。因此,不是公开类层次结构,而是将其隐藏在实用程序类中。

Live example

当然,any_view 只是为了避免在传递范围类型时模板函数。您可以直接将范围具体化为 vector :

auto base_view =
    rv::all(derived_container) | rv::transform([](auto& e) -> Base* { return &e; });

std::vector<Base*> base_container = ranges::to<std::vector>(base_view);

这将避免迭代期间的开销,但需要为新 vector 分配内存。

关于c++ - std::vector 的协变包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56342493/

相关文章:

c++ - 将数据从 Delphi DLL 传递到 C++ 应用程序

c++ - 为什么当我调用 UpdateData(FALSE) 时我的对话框没有立即更新?

c# - 最长递增子序列的数量

c# - 具有通用处理程序和查询的 Mediatr

c# - 使用泛型类型接口(interface)创建对象实例时出现编译错误

c++ - OpenCV findContours 不工作

c++ - 使用深度测试正确渲染 OpenGL 中的表面

c#-4.0 - 为什么泛型类型参数的 .NET 4 差异不适用于类?

scala - 试图找到更简单的方法来从特征中引用子类的类型

c# - 如何检查 `IEnumerable<T1>` 是否与 `IEnumerable<T2>` 协变?