Call member functions of members of elements of a container with for_each?
Question
Confusing title, hopefully some code will clarify:
struct MyNestedType {
void func();
};
struct MyType {
MyNestedType* nested;
}
std::vector<MyType> vec;
// ... populate vec
// I want something approximating this line, but that doesn't use made-up C++!
std::for_each(vec.begin(), vec.end(), std::mem_fun_ref(&MyType::nested->func));
So basically I want to call a method on each element of the container, but it's not actually a method of the type, it's some method on a contained type... I know I could write a function object to 'pass on' the call but there are a few methods I'd like to call and that will get messy.
Any ideas?
Solution
You can use such functor
template <typename T, T* MyType::* TMember, void (T::* TNestedMember)() >
struct Caller {
Caller() {
}
template <typename TObject>
void operator()(TObject object) {
(object.*TMember->*TNestedMember)();
}
};
To solve your problem
struct MyNestedType {
MyNestedType(int a):
a_(a){
}
void func() {
std::cout << "MyNestedType::func " << a_ << std::endl;
}
void foo() {
std::cout << "MyNestedType::foo " << a_ << std::endl;
}
int a_;
};
struct MyType {
MyNestedType* nested;
};
int main()
{
std::vector<MyType> vec;
std::auto_ptr<MyNestedType> nt1(new MyNestedType(2));
std::auto_ptr<MyNestedType> nt2(new MyNestedType(5));
MyType t1 = {nt1.get()};
MyType t2 = {nt2.get()};
vec.push_back(t1);
vec.push_back(t2);
std::for_each(vec.begin(), vec.end(),
Caller<MyNestedType, &MyType::nested, &MyNestedType::func>());
std::for_each(vec.begin(), vec.end(),
Caller<MyNestedType, &MyType::nested, &MyNestedType::foo>());
}
OTHER TIPS
Why don't you just use a simple for-loop?
for(vector<MyType>::iterator i = vec.begin(); i != vec.end(); ++i)
i->nested->func();
Alternatively, you could use lambda expressions or boost::foreach
FOREACH(MyType x, vec)
x.nested->func();
You can build your up expression with binders and mem_funs, but this will get very messy and confusing! There is no advantage in putting everything in one std::foreach line.
Maybe you could add func() into struct MyType():
void func(...) {
nested->func(...);
}
This way you will not have separate adapter functor, but instead an aggregation inside wrapper type, i.e. quite regular OOP technique.
If you want to use for_each you need a functor.
struct CallMyFunc
{
void operator()(MyType& obj) { obj.nested->func();}
};
std::for_each(vec.begin(), vec.end(), CallMyFunc());
Alternatively I would use the boost::FOREACH syntax described by:
Dario: Call member functions of members of elements of a container with for_each?
Yes it is possible to use boost::bind
for this, but it gets messy. Please use @Dario's boost for-each way, but here is the boost::bind
one for the sake of completeness
std::for_each(vec.begin(), vec.end(),
boost::bind(&MyNestedType::func, boost::bind(&MyType::nested, _1)));
Anyway, as it happens, we don't even get a nice one-liner with this :)
How about using Boost's transform_iterator
?