Std:: function с нестационарными функциями-членами

Я пытаюсь понять концепцию и ошибку. что с этим не так?

class A
{
public:
    A()
    {
        std::function<void(int)> testFunc(&A::func);
    }

private:
    void func(int) {}
}

мой вопрос: возможно ли создать какой-либо объект, способный вызвать член определенного экземпляра, где std:: function действует как указатель на функцию-член, за исключением того, что не может быть использовано нечеткое определение типа, которое невозможно использовать как функциональные параметры в наследующих классах. например:

class A
{
public:
    A()
    {
         index[WM_CREATE] = &A::close;
         index[WM_DESTROY] = &A::destroy;
    }

protected:
    map<UINT msg, void (A::*)(HWND, UINT , WPARAM, LPARAM)> index;
    void close(HWND,UINT, WPARAM, LPARAM);
    void destroy(HWND, UINT, WPARAM, LPARAM);
};

class B : public A
{
public:
    B()
    {
        index[WM_CREATE] = &B::create; // error because it not a pointer of type A::*
    }
private:
    void create(HWND, UINT, WPARAM, LPARAM);

};

Я думаю, что я нахожусь на правильном пути использования std:: functions следующим образом:

class A
{
public:             //         Gigantic stl error with these two
    A()             //                         |
    {               //                         V
         index[WM_CREATE] = std::function<void(HWND, UINT, WPARAM, LPARAM>(&A::close);
         index[WM_DESTROY] = std::function<void(HWND, UINT, WPARAM, LPARAM>(&A::destroy);
    }

protected:
    map<UINT msg, std::function<void(HWND, UINT, WPARAM, LPARAM)> > index;
    void close(HWND,UINT, WPARAM, LPARAM);
    void destroy(HWND, UINT, WPARAM, LPARAM);
};

class B : public A
{
public:                    //               and this one
    B()                    //                     |
    {                      //                     V
        index[WM_CREATE] = std::function<void(HWND, UINT, WPARAM, LPARAM)>(&B::create);
    }
private:
    void create(HWND, UINT, WPARAM, LPARAM);

};

если кто-то может объяснить, что означают эти гигантские критические ошибки и как их исправить, я бы очень признателен.

Ответ 1

Я думаю, что проблема, с которой вы сталкиваетесь, заключается в том, что для функции-члена требуется не только указатель на функцию, но и указатель на вызывающий объект. Другими словами, функции-члены имеют дополнительный неявный аргумент, который является указателем на вызывающий объект.

Чтобы установить функцию-член в std:: функцию, вам нужно использовать std:: bind следующим образом:

std::function<void(int)> testFunc(std::bind(&A::func, this, _1));

Это связывает этот указатель текущего экземпляра с этой функцией, поэтому у него есть указатель на функцию и экземпляр объекта, для которого достаточно информации для правильного вызова функции. Аргумент _1 указывает, что первый явный аргумент будет предоставлен при вызове функции.

Ответ 2

мой вопрос: возможно ли создать какой-либо объект, способный вызвать член определенного экземпляра

В этом случае единственная потерянная информация - это то, какой конкретный экземпляр должен использовать объект std::function: &A::func не может использоваться сам по себе (например, (this->*&A::func)(0) использует &A::func с экземпляром *this). Попробуйте:

std::function<void(int)> testFunc = std::bind(&A::func, this);

(Будьте осторожны, чтобы std::bind(&A::func, *this) и std::bind(&A::func, this) имели слегка отличную семантику.)

Ответ 3

С c ++ 11 вы также можете использовать лямбды, которые немного легче читать, чем std::bind:

index[WM_CREATE] = [this](HWND h, UINT u, WPARAM w, LPARAM l)
{
  create(h, u, w, l);
}