views:

100

answers:

6

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.

A: 

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;
}
Tareq A. Siraj
A: 

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?

Klaim
+3  A: 

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.

Tony
That idea is contained in the entry I mentioned in the last sentence.
David
+1  A: 

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.

Mark B
I assumed that 'this' was implicit in the function signature. There are many questions on SO that ask about arrays of pointers-to-member-functions. I'm curious what distinguishes them from STL containers.
David
The parameter `this` is implicit in the signature. The *value* of the parameter is not. How could it be? What distinguishes an array of pointers to member functions from a standard library container? The same thing that distinguishes an array of integers from a standard library container.
Dennis Zickefoose
+1  A: 

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

DeadMG
+1  A: 

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.

Dennis Zickefoose
That was an excellent explanation. I'm grateful for it. I gather that likewise, I could call v[1].*f[2]() and I would get 'two: 1'.
David
@David, I chose really bad names. `(v[0].*f[1])()` would give the result you expect, but I suspect you just got got confused by my hasty naming scheme. `v[1]` has the value 2, and `f[2]` points to the function `One`.
Dennis Zickefoose