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

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

本文关键字:两个 同类 向量 设置 何设置 一个 std 另一个 vector      更新时间:2023-10-16

有没有办法用另一个设置一个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 值未初始化?

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

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

来自<algorithm>标头的transform与来自<iterator>back_inserter一起可用于使它像这样:

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

您还可以使其更具表现力。Lambdas是一种简单且最有效的表达人类可读概念的方式,如惰性函数(如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));
}

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

我认为你不能得到更优化的。您可以确保预先vb保留足够的空间以避免不必要的重新分配,并使用基于范围的 for 循环和emplace_back使循环更加简洁:

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