最快的方法std :: vector <derived>到std :: vector <base />

时间:2017-03-29 03:05:21

标签: c++ c++11 inheritance vector stl

这是测试代码:

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;
}

它有效,但需要额外复制BA。如果AB是一个大对象,则可能非常慢。更好的选择是:

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>而无需任何额外费用?

2 个答案:

答案 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
 }