views:

277

answers:

6

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?

A: 

How about using Boost's transform_iterator?

James Hopkin
+7  A: 

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.

Dario
Of course there's an advantage! It'll make me feel really really clever!Point taken, though. Perhaps I'll just leave it as a for loop like I have it now.
Ben Hymers
of course, boost foreach was my first thought once i imagined how messy it would become with boost::bind :) +1 indeed
Johannes Schaub - litb
+2  A: 

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.

A ruddy good point. I've accepted another answer since it answers the question, but I rated this answer up since it's the advice I'm probably going to take!
Ben Hymers
Thanks, I'm starting to collect such "accepts" ;)
+2  A: 

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: http://stackoverflow.com/questions/857786/call-member-functions-of-members-of-elements-of-a-container-with-foreach/857878#857878

Martin York
+3  A: 

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>());
}
Mykola Golubyev
Brilliant, that's exactly the answer I was hoping for, though some of the other comments have made me think that maybe I was looking for the wrong thing ;)
Ben Hymers
Good answer, you divined that Ben wanted to parametrize both the method AND the nested member object, though it was not stated.
veefu
Ben Hymers
+2  A: 

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 :)

Johannes Schaub - litb