How do I set std :: vector with another, where two are vectors of different classes?
Is there a way to set std :: vector with another, where two are vectors of different classes?
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));
}
Anything you want (pseudocode):
vb = va;
with uninitialized values B :: b?
source to share
I would like to point out that since for ranges based on ranges, I had little desire to use simple algorithms such as converting very often. Hope you can understand why.
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);
source to share
transform
from <algorithm>
header along with back_inserter
from <iterator>
can be used to do it like this:
std::transform(va.begin(), va.end(), std::back_inserter(vb),
[](A x) -> B { return B(x.a, commonB); });
UPDATE
If it commonB
does not have a global scope, its name should be written (written in square brackets of the lambda definition):
std::transform(va.begin(), va.end(), std::back_inserter(vb),
[commonB](A x) -> B { return B(x.a, commonB); });
source to share
I don't think you can get much more optimal. You can make sure enough space is reserved in vb
upfront to avoid unnecessary reallocations and use a loop for the loop and emplace_back
to make the loop more concise:
vb.reserve(va.size());
for (const auto& a : va)
vb.emplace_back(a, commonB);
source to share
You can generalize with a transform function and a lambda.
Everything will be perfectly optimized when compiled with -O2 or better:
Note the use reserve()
to prevent reallocation when the vector grows.
#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);
}
You can also make it more expressive. Lambdas are a simple and optimally efficient way of expressing human-readable concepts such as lazy functions (e.g. Haskell et al.):
auto vb = transform_to_Bs(va, with_common_b(123));
Which can be implemented this way:
#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));
}
Applying perfect forwarding here is a gross over-optimization. The compiler actually keeps all redundant copies of function objects.
source to share