So I have two containers
set<Person>
vector<Person*>
Is there any way for the following transform lambda code to be modified such that either container can be used?
transform(container.begin(), container.end(), back_inserter(data),
[](const Person* p) { return PairResults(p->getTime(), p->getName()); }
);
Right now I'm only able to get it to work on the vector.
Thanks.
Many thanks to Andrew for his help on this one!
You can do it using a little trick with function overload: define two functions that produce a pointer to Person
, like this:
const Person* make_ptr(const Person* p) { return p; }
const Person* make_ptr(const Person& p) { return &p; }
The next problem is unifying the type of the element for the lambda: unfortunately, it is not legal to say [](auto p) {...}
and let the compiler pick Person
or Person*
for you. Using a template solves this problem:
template<typename T, typename R>
void xform(vector<T>& from, vector<R>& to) {
transform(from.begin(), from.end(), back_inserter(to),
[&](T &p) { return PairResults(make_ptr(p)->getTime(), make_ptr(p)->getName()); }
);
}
Now everything works - you can call xform
with a container of Person
or Person*
, and get the correct results.
Demo on ideone.
You could use a proxy object that accepts pointer to Person or ref to Person and gives them both pointer semantics:
Live example: http://ideone.com/Wk2VMx
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
#include <string>
struct Person {
int age;
std::string name;
};
class PersonProxy {
public:
PersonProxy(Person& p)
: person(&p) {}
PersonProxy(Person* p)
: person(p) {}
Person& operator*() { return *person; }
Person* operator->() { return person; }
private:
Person* person;
};
int main()
{
std::vector<Person> p1;
p1.push_back(Person{42, "Bob"});
Person bill{30, "Bill"};
std::set<Person*> p2;
p2.insert(&bill);
std::vector<int> data;
auto the_lambda = [](PersonProxy pp) {return pp->age;};
std::transform(p1.begin(), p1.end(), std::back_inserter(data), the_lambda);
std::transform(p2.begin(), p2.end(), std::back_inserter(data), the_lambda);
for (int age : data)
{
std::cout << age << "\n";
}
}
Another approach would be to use a functor instead of the lambda, and define operator()(Person&)
and operator()(Person*)
, but the approach above is to provide a type with which you can write the lambdas, and for which implicit conversions from Person
and Person*
are available.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With