std::vector<std::unique_ptr<Base>>
和
std::vector<std::unique_ptr<Derived>>
不是
covariant
,并且它们之间不存在转换函数,因此不能简单地将其中一个视为另一个。
它们是完全不同的、不相关的类型。
多态存储
如果您需要多态存储,为什么不直接使用
std::vector<std::unique_ptr<基础>>
处处
您可以插入
std::unique_ptr<Derived>
像这样:
// note: passing by reference to avoid having to move the vector
// (copying would be illegal)
void g(const std::vector<std::unique_ptr<Test::Base>> &v)
{
for (const std::unique_ptr<Test::Base> &vi : v)
{
std::cout << vi->f(1, 2) << " ";
}
std::cout << std::endl;
}
int main()
{
std::vector<std::unique_ptr<Test::Base>> v;
v.emplace_back(std::make_unique<Test::A>());
v.emplace_back(std::make_unique<Test::A>());
g(v);
}
接受协方差类型的向量
或者,如果您只需要存储
std::vector<Derived>
但希望将其传递到函数中
Base
值,您可以执行以下操作:
#include <concepts>
// C++20 version using concepts
template <std::derived_from<Test::Base> Derived>
void g(std::vector<Derived> &v)
{
for (Test::Base &vi : v)
{
std::cout << vi.f(1, 2) << " ";
}
std::cout << std::endl;
}
// C++17 counterpart
template <typename Derived>
auto g(std::vector<Derived> &v)
-> std::enable_if_t<std::is_base_of_v<Test::Base, Derived>>
{ ... }
呼叫
g
,我们需要申报
std::vector<Test::A> v;
在里面
main
。
如果我们使用范围,我们可以使这个函数更加通用,这样我们就不再依赖
std::vector
明确地
// C++20 version
template <std::ranges::input_range Range>
requires (std::derived_from<std::ranges::range_value_t<Range>, Test::Base>)
void g(Range &v)
{
for (Test::Base &vi : v)
{
std::cout << vi.f(1, 2) << " ";
}
std::cout << std::endl;
}
// C++17 version would be much more difficult because we lack the proper type traits.
// If we accepted two iterators, it would become easier.
template <typename ForwardIt>
auto g(ForwardIt begin, ForwardIt end)
-> std::enable_if_t<std::is_base_of_v<Test::Base, typename std::iterator_traits<ForwardIt>::value_type>>
{ ... }
// call this function like g(v.begin(), v.end())
注意:您也可以让模板不受约束,这将使其更容易在C++17中实现。