如何设置一个 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);
有没有办法设置一个 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);