这是测试代码:
class A{};
class B : public A{};
void Test(const std::vector<A>& a)
{
}
int main()
{
std::vector<A> a;
std::vector<B> b;
Test(a);
Test(b);//Compiler Error
return 0;
}
由于std::vector<A>
和std::vector<B>
类型不同,我们无法从一个转换为另一个。
可选方式可以是:
class A{};
class B : public A{};
void Test(const std::vector<A>& a)
{
}
int main()
{
std::vector<A> a;
std::vector<B> b;
Test(a);
Test(std::vector<A>(b.begin(), b.end()));
return 0;
}
它有效,但需要额外复制B
到A
。如果A
或B
是一个大对象,则可能非常慢。更好的选择是:
class A{};
class B : public A{};
void Test(const std::vector<A>& a)
{
}
int main()
{
std::vector<A> a;
std::vector<B> b;
Test(a);
Test(std::vector<A>(std::make_move_iterator(b.begin()), std::make_move_iterator(b.end())));
return 0;
}
因为它只是移动iter而不是整个B
类,所以它需要更好的性能。但是还有一些额外的成本 - 如果b
是一个包含大量项目的非常大的向量,迭代也会减慢我的代码。
所以我想知道是否有办法直接将std::vector<B>
转换为std::vector<A>
而无需任何额外费用?
答案 0 :(得分:1)
一种方法是使向量成为Test函数的模板参数。呼叫代码将保持不变,无需复制。
#include <vector>
#include <iostream>
class A{
public:
virtual void print() const {
std::cout << "A" << std::endl;
}
};
class B : public A{
virtual void print() const {
std::cout << "B" << std::endl;
}
};
template <typename ContainerA>
void Test(const ContainerA& aas)
{
for(const A& a:aas) {
a.print();
}
}
int main()
{
std::vector<A> a;
a.push_back(A());
std::vector<B> b;
b.push_back(B());
Test(a);
Test(b);
return 0;
}
答案 1 :(得分:1)
我不知道它对你有用,但我能想到的最好的就是将std::vector<Derived>
传递给函数并将元素迭代为Base
元素。
像
这样的东西template <typename D>
void Test (std::vector<D> const & v)
{
for ( A const & elem : v )
{
// use elem
}
}
使用SFINAE,您只能为Test()
或Base
元素的向量启用Base
,如下所示
template <typename D>
typename std::enable_if<std::is_base_of<A, D>::value>::type
Test (std::vector<D> const & v)
{
for ( A const & elem : v )
{
// use elem
}
}
所以你有
int main ()
{
std::vector<A> a;
std::vector<B> b;
std::vector<int> c;
Test(a); // compile
Test(b); // compile
// Test(c); // compiler error
}