Question

Say I have a class:

class A
{
public:
  void doSomething();
}

Where doSomething does something that explicitly relies on the internal state of the instance of A.

Now, I have a situation where I have a bunch of things of type A laying around, but I only want to call doSomething from a strict subset of them, so I want to stick them on the list. In particular, what I really want to do is stick pointers to individual doSomethings() in the list.

Can I do it? Do I declare it like:

std::list<(A::*)()> aDoSomethings;

I read this entry, it makes sense and I will go that route if I need to.

Was it helpful?

Solution

It seems like you're confused about how member function pointers work. For a given class, there is only a single instance of any given function. They are differentiated by the use of the implicit parameter this. Basically, you can pretend you have the following mapping.

struct Struct { void Function(); }
Struct a;
a.Function();

turns into

struct Struct { }
void Function(Struct* this);
Struct a;
Function(&a);

So if you have a bunch of Struct objects, and you want to call Function on a small set of them, you don't store Function, you store Struct.

Pointers to member functions are used when you have multiple functions, that you want to call selectively. So if you have two functions in your class, both of which take no paramters and return void, void (Struct::*)() can point to either of them. But it still points to a specific function, of which there's only one. You still need to provide the this parameter.

struct Struct {
  Struct(int v) : value(v) { }
  void One() { cout << "one: " << value << endl; }
  void Two() { cout << "two: " << value << endl; }
  int value;
};

int main()
{
  std::vector<Struct> v;
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);

  std::vector<void (Struct::*)()> f;
  f.push_back(&Struct::One);
  f.push_back(&Struct::Two);
  f.push_back(&Struct::One);

  for(int i = 0; i < 3; ++i)
    (v[i].*f[i])();
}  

Not the best example, but it gets the point across. You can mix and match objects, with member functions.

*edit: An example without containers getting in the way

Struct a(5), b(10);
void (Struct::*one)() = &Struct::One;
void (Struct::*two)() = &Struct::Two;

(a.*one)();
(b.*one)();
(a.*two)();
(b.*two)();

Note the extra parenthesis. a.*one() is insufficient.

OTHER TIPS

Have you considered the simple OO approach:

struct Can_Do_Something
{
    virtual void doSomething() = 0;
};

class A : public Can_Do_Something
{
    ...
};

std::list<Can_Do_Something*> my_list;

my_list[n]->doSomething();

This is restrictively maintaining access to the part of A's interface - inherited through the Can_Do_Something type - that you plan to access via the list. It documents and enforces that restriction.

If you have a preference for something closer to your original vision, consider...

#include <iostream>
#include <vector>
#include <boost/function.hpp>

struct A
{
    A(int n) : n_(n) { }

    int f(int x) { std::cout << "A::f() this " << (void*)this
                           << ", n_ " << n_
                           << ", x_ " << x << '\n'; }

    int n_;
};

int main()
{
    typedef boost::function<int (int n)> Function;
    typedef std::vector<Function> Functions;

    Functions functions;
    A a1(1), a2(2), a3(3);

    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a1));
    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a2));
    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a3));

    for (Functions::iterator i = functions.begin();
            i != functions.end();
            ++i)
        (*i)(42);
}

Here, boost::function is used to create a callback to the specific functions you're interested in.

A member function pointer doesn't have a pointer to a particular instance: It describes how to call a member function with a certain signature given a this pointer and parameters.

Instead, put pointers to the objects you care about into the list, and then iterate over that list, calling doSomething on each item.

You should check out boost::function and boost::bind.

Yes, you probably want something like:

#include <vector>
#include <iostream>
#include <string>

using namespace std;

class A {
  string m_name;

  public:
    A(const string& name) : m_name(name) {} 
    void doSomething() { cout << m_name << "::doSomething()" << endl; }
};

int main(void) {
  A f1("f1");
  A f2("f2");
  A f3("f3");
  A f4("f4");
  vector<A*> foo_list;
  foo_list.push_back(&f1);
  foo_list.push_back(&f3);

  for (vector<A*>::iterator it = foo_list.begin(); it != foo_list.end(); *it++) {
    static_cast<A*>(*it)->doSomething();
  }

  return 0;
}

If my understanding is correct, you want to have a list of pointers to functions member that have to be doSomething()?

Then you can have a list of function pointers to a member of your class, but you'll need to provide the associated object with it, so why not simply keep a list of (pointers to) the objects?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top