Re: member iterator - request for comment
Mikosz <mikoszrrr@gmail.com> writes:
Paul, thanks for the quick reply.
On 22 Cze, 01:35, Paul Bibbings <paul.bibbi...@gmail.com> wrote:
Mikosz <mikosz...@gmail.com> writes:
[...] to perform some action on one of the members of each of the
collection's elements. I couldn't find any solutions within the STL,
#include <vector>
#include <set>
#include <algorithm>
struct A {
A(int v) : val(v) { } // added for convenience here
int val;
};
struct val_functor {
int operator()(A a) { return a.val; }
};
int main()
{
std::vector<A> as;
std::set<int> vals;
for (int i = 0; i < 10; i++) as.push_back(i);
std::transform(as.begin(),
as.end(),
std::inserter(vals, vals.begin()),
val_functor());
}
Good point, I actually forgot about 'transform'. However, a solution
that would allow me not to implement an extracting functor would be
much neater. Again - I don't know of any existing solutions, so I
crafted my own. What do you think of this:
From the `solution' that you give below, what I understand you to be
requiring here is, not that you don't want to implement an extracting
functor as such (since, essentially, that is what you do), but that you
don't want to have to implement *separate* functors for different
classes and for different members of those classes; essentially, what
you are looking for is a /generic/ solution. Would that be right?
template<class PointerToMember, class Member>
class Extractor {
public:
Extractor(PointerToMember ptr) :
ptr_(ptr) {
}
template<class T>
Member& operator()(T& object) {
return object.*ptr_;
}
template<class T>
const Member& operator()(const T& object) const {
return object.*ptr_;
}
private:
PointerToMember ptr_;
};
template <class Member, class PointerToMember>
Extractor<PointerToMember, Member> makeExtractor(PointerToMember ptr)
{
return Extractor<PointerToMember, Member>(ptr);
}
struct A {
A(int v) :
val(v) {
}
int val;
};
int main() {
std::vector<A> as;
std::set<int> vals;
for (int i = 0; i < 10; i++) {
as.push_back(i);
}
std::transform(as.begin(), as.end(), std::inserter(vals,
vals.begin()), makeExtractor<int>(&A::val));
std::copy(vals.begin(), vals.end(),
std::ostream_iterator<int>(std::cout, ", "));
}
Given the aim as I have understood it, I think that you can do just a
little better and get template argument deduction to do more for you.
Also, you don't need both of your overloads for the function call
operator. Since neither modify the object on which the operator is
called, the const version is sufficient.
Putting all this together, I might suggest something like the following,
which is, essentially, a refactoring of your idea applying a `better'
parameterization:
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
#include <iterator>
template<class T, class M>
class Extractor
{
public:
Extractor(M (T::*ptr))
: ptr_(ptr)
{ }
M operator()(const T& t) { return t.*ptr_; }
private:
M (T::*ptr_);
};
template<class T, class M> // *both* T and M can be deduced here
Extractor<T, M> makeExtractor(M (T::*ptr))
{
return Extractor<T, M>(ptr);
}
struct A
{
A(int i) : val(i) { }
int val;
};
int main()
{
std::vector<A> as;
std::set<int> vals;
for (int i = 0; i < 10; i++) {
as.push_back(i);
}
std::transform(as.begin(),
as.end(),
std::inserter(vals, vals.begin()),
makeExtractor(&A::val));
std::copy(vals.begin(),
vals.end(),
std::ostream_iterator<int>(std::cout, ", "));
}
Here, the main difference is that *both* template arguments to
makeExtractor can be deduced from the single function call argument
whereas, in your implementation, you had to provide:
makeExtractor<int>(&A::val);
Regards
Paul Bibbings
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]