如何设置一个 std::vector 与另一个 std::vector,其中两个是不同 类 的向量?

How to set an std::vector with another one, where the two are vectors of different classes?

有没有办法设置一个 std::vector 与另一个 std::vector,其中两个是不同 类 的向量?

struct A {
   int a;
};

struct B {
   int a, b;
   B(int _a, int _b) : a(_a), b(_b) {}
};

int commonB = 123;

std::vector<A> va;
std::vector<B> vb;

// Fill va...

// Code I would like to optimise:
for(size_t i = 0; i < va.size(); ++i) {
    vb.push_back(B(va[i].a, commonB));
}

任何东西(伪代码):

vb = va;

B::b 值未初始化?

我认为您无法获得更多优化。您可以确保预先在 vb 中保留足够的 space 以避免不必要的重新分配,并使用基于范围的 for 循环和 emplace_back 使循环更简洁:

vb.reserve(va.size());
for (const auto& a : va)
    vb.emplace_back(a, commonB);

transform 来自 <algorithm> header 和 back_inserter 来自 <iterator> 可以用来做这样的事情:

std::transform(va.begin(), va.end(), std::back_inserter(vb),
    [](A x) -> B { return B(x.a, commonB); });

更新

如果commonB没有全局作用域,应该捕获它的名字(写在lambda定义的方括号中):

std::transform(va.begin(), va.end(), std::back_inserter(vb),
    [commonB](A x) -> B { return B(x.a, commonB); });

您可以使用转换函数和 lambda 进行概括。

当您使用 -O2 或更好的编译时,所有内容都将得到完美优化:

注意使用 reserve() 来防止向量增长时重新分配。

#include <vector>
#include <algorithm>

struct A {
   int a;
};

struct B {
   int a, b;
   B(int _a, int _b) : a(_a), b(_b) {}
};

template<class TransformFunction>
std::vector<B> transform_copy(std::vector<A>& source, TransformFunction&& trans)
{
    std::vector<B> result;
    result.reserve(source.size());
    std::transform(source.begin(), source.end(), std::back_inserter(result), trans);
    return result;
}

int main()
{
    int commonB = 123;
    auto transform_function = [commonB](A const& source) {
        return B(source.a, commonB);
    };

    std::vector<A> va;
    std::vector<B> vb = transform_copy(va, transform_function);

}

你也可以让它更有表现力。 Lambda 是一种简单且最有效的方式来表达人类可读的概念,例如惰性函数(例如 Haskell 等):

auto vb = transform_to_Bs(va, with_common_b(123));

可以这样实现:

#include <vector>
#include <algorithm>

struct A {
    int a;
};

struct B {
    int a, b;

    B(int _a, int _b) : a(_a), b(_b) {}
};


extern std::vector<A> get_As();

int main() {

    auto with_common_b = [](auto &&commonB) {
        return [commonB](auto &&a) {
            return B(a.a, commonB);
        };
    };

    auto transform_to = [](auto &&target, auto &&source, auto &&transform_function) {
        target.reserve(source.size());
        std::transform(source.begin(), source.end(),
                       std::back_inserter(target),
                       std::forward<decltype(transform_function)>(transform_function));
    };

    auto transform_to_Bs = [transform_to](auto &&va, auto &&transform_function) {
        std::vector<B> result;
        transform_to(result, va, std::forward<decltype(transform_function)>(transform_function));
        return result;
    };

    std::vector<A> va = get_As();

    auto vb = transform_to_Bs(va, with_common_b(123));
}

在这里应用完美转发是一种严重的过度优化。实际上,编译器会删除函数对象的所有冗余副本。

我只想指出,自从基于范围的 for 循环以来,我并没有太大的愿望经常使用像转换这样的简单算法。我希望你能明白为什么。

std::transform(va.begin(), va.end(), std::back_inserter(vb),
    [commonB](A x) -> B { return B(x.a, commonB); });

for (auto& e : va)
    vb.emplace_back(e.a, commonB);