- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我想要 std::vector
的协变包装器.我的想法是做这样的事情:
BaseVector<B>
谁的begin
和 end
方法只是转发给纯虚函数。DerivedVector<B, D>
包裹着 std::vector<D>
.它的begin
和 end
方法将隐藏基类的方法,并且它将实现基类转发到的虚拟方法。这样,如果你有一个指向 BaseVector
的指针你可以迭代基类实例,如果你有一个 DerivedVector
您可以迭代派生类实例的指针。
(编辑:显然 BaseVector
不一定支持插入,因为它不知道它包含的对象的类型。也许这意味着“vector ”不是最好的名字为此;我愿意接受建议。谢谢@CygnusX1。)
对于 DerivedVector
begin 和 end 方法类可以直接转发到 std::vector
的。
问题:我如何实现 BaseVector
的方法? begin
和 end
转发?我是否必须编写自己的迭代器类来包装 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,我会创建一个类似的包装器。因此,不是公开类层次结构,而是将其隐藏在实用程序类中。
当然,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/
在我的设置中,我试图有一个界面 Table继承自 Map (因为它主要用作 map 的包装器)。两个类继承自 Table - 本地和全局。全局的将有一个可变的映射,而本地的将有一个只有本地条目的映射。
Rust Nomicon 有 an entire section on variance除了关于 Box 的这一小节,我或多或少地理解了这一点和 Vec在 T 上(共同)变体. Box and Vec
我是一名优秀的程序员,十分优秀!