4

我制作了包含函数的向量,但它们没有参数列表。此外,他们不在班级内。我有一个名为 的类Dialog,我需要存储具有特定签名的函数指针。这是我对这些函数的 typedef:

typedef INT_PTR (*MsgHandler)(WPARAM,LPARAM);

但是,由于包含这些MsgHandler' 的向量将在我的Dialog类中,这将由我的CMainWnd类继承,所以当我尝试 push_back 函数时,函数的签名与MsgHandler. 这是我的代码,尝试 push_back 向量中的函数的 4 种变体,以及每个变体产生的错误:

typedef INT_PTR (*MsgHandler)(WPARAM,LPARAM);

class Dialog
{
protected:
    Dialog(void); // Must be inherited
    vector<MsgHandler> Handlers;
}

class CMainWnd : public Dialog
{
public:
    INT_PTR MyHandler(WPARAM wp, LPARAM lp) {
        return TRUE;
    }

    CMainWnd(void) {
        // Attempt 1: Handlers.push_back(MyHandler);
        // Attempt 2: Handlers.push_back(&MyHandler);
        // Attempt 3: Handlers.push_back(CMainWnd::MyHandler);
        // Attempt 4: Handlers.push_back(&CMainWnd::MyHandler);
    }
};

尝试 1 产生以下错误:

error C3867: 'CMainWnd::MyHandler': function call missing argument list; use '&CMainWnd::MyHandler' to create a pointer to member

尝试2产生:

error C2276: '&' : illegal operation on bound member function expression

尝试 3 产生:

error C3867: 'CMainWnd::MyHandler': function call missing argument list; use '&CMainWnd::MyHandler' to create a pointer to member

尝试 4 产生:

error C2664: 'std::vector<_Ty>::push_back' : cannot convert parameter 1 from 'INT_PTR (__thiscall CMainWnd::* )(WPARAM,LPARAM)' to 'const MsgHandler &'

我认为尝试 4 最接近正确,但如前所述,由于该函数是成员,它会改变签名。如何将函数指针存储在继承类中定义的向量中Dialog

  • 有一个返回类型INT_PTR
  • 有两个参数,第一个是 a WPARAM,第二个是 aLPARAM
  • 是派生类的成员,其构造函数是将它们添加到向量中的构造函数

我听说过使用它boost::function来做这样的事情,但我已经查阅了它的文档,但我不知道如何使用它,这一切让我感到困惑。我非常想将函数添加到向量中,就好像它们是变量一样,而不是让我的代码陷入绑定操作等等。(可能只是因为我对增强功能一无所知)。

我在这里做错了什么,或者我可以boost::function用来做这个吗?顺便说boost::function一句,我尝试将向量声明为vector<boost::function<INT_PTR(WPARAM,LPARAM)>>并尝试添加MyHandler它,但这不起作用。如果不需要,我宁愿不使用 boost,但是如果有人建议这样做的 boost 方式,请说明我该怎么做?

4

4 回答 4

4

想一想:当你创建一个函数指针向量时,向量的每个元素的大小是多少?没错,就是函数指针的大小。现在,你怎么能期望它保存指向函数的指针以及指向应该调用函数的对象的指针?

C++ 语言功能是围绕“按使用付费”原则设计的。所以函数指针尽可能的轻。现在,您想要的实际上是代表。Delegates 不是 C++ 的语言特性,所以,不管你喜不喜欢,你都需要使用 boost::function 之类的东西(或者自己写)。顺便说一下,有比 boost::function 更快的委托解决方案,您可以检查:this code project and this one

下面是使用 boost::function 的方法:

#include <vector>
using namespace std;
#include <boost/function.hpp>
#include <boost/bind.hpp>

typedef int INT_PTR;
typedef int WPARAM;
typedef int LPARAM;

//typedef INT_PTR (*MsgHandler)(WPARAM,LPARAM);
typedef boost::function<INT_PTR(WPARAM,LPARAM)> MsgHandler;

class Dialog
{
protected:
    Dialog(void){} // Must be inherited
    vector<MsgHandler> Handlers;
};

class CMainWnd : public Dialog
{
public:
    INT_PTR MyHandler(WPARAM wp, LPARAM lp) {
        return true;
    }

    CMainWnd(void) {
        // Attempt 1: Handlers.push_back(MyHandler);
        // Attempt 2: Handlers.push_back(&MyHandler);
        // Attempt 3: Handlers.push_back(CMainWnd::MyHandler);
        // Attempt 4: Handlers.push_back(&CMainWnd::MyHandler);
    Handlers.push_back(boost::bind(&CMainWnd::MyHandler, this, _1,_2));
    }
};

int main() {
    CMainWnd w;

}

这是不可能的快速代表:(当然包含正确设置的路径)

#include <vector>
using namespace std;
#define SRUTIL_DELEGATE_PREFERRED_SYNTAX
#include <srutil/delegate/delegate.hpp>

typedef int INT_PTR;
typedef int WPARAM;
typedef int LPARAM;

typedef srutil::delegate<INT_PTR(WPARAM,LPARAM)> MsgHandler;

class Dialog
{
protected:
    Dialog(void){} // Must be inherited
    vector<MsgHandler> Handlers;
};

class CMainWnd : public Dialog
{
public:
    INT_PTR MyHandler(WPARAM wp, LPARAM lp) {
        return true;
    }

    CMainWnd(void) {
    Handlers.push_back(MsgHandler::from_method<CMainWnd, 
              &CMainWnd::MyHandler>(this));
    }
};

int main() {
    CMainWnd w; 
}
于 2012-09-27T07:18:04.103 回答
4

如果您可以访问 C++11,这就是 lambda 真正大放异彩的地方。我将稍微更改您的代码,只是因为让它为我工作稍微容易一些,但您应该能够很容易地根据您的需要修复它:

#include <vector>
#include <functional>
#include <iostream>

class Dialog
{
protected:
    Dialog() { } // Must be inherited
    std::vector<std::function<bool (int, int)>> Handlers;
};

class CMainWnd : public Dialog
{
public:
    bool MyHandler(int wp, int lp) 
    {
        std::cout << "(" << wp << ", " << lp << ")\n";
        return true;
    }

    CMainWnd() 
    {
       Handlers.push_back([this](int wp, int lp) -> bool { return this->MyHandler(wp, lp); });
       std::cout << Handlers[0](1,1) << "\n";
    }
};

int main()
{
    CMainWnd c;
    return 0;
}

编辑:当使用 C++03 和 boost 时:

#include <boost/function.hpp>
#include <boost/bind.hpp>

class Dialog
{
protected:
    Dialog() { } // Must be inherited
    std::vector<boost::function<bool (int, int)> > Handlers;
};

class CMainWnd : public Dialog
{
public:
    bool MyHandler(int wp, int lp) 
    {
        std::cout << "(" << wp << ", " << lp << ")\n";
        return true;
    }

    CMainWnd() 
    {
       Handlers.push_back(boost::bind(&CMainWnd::MyHandler, this, _1, _2));
       std::cout << Handlers[0](1,1) << "\n";
    }
};
于 2012-09-27T07:32:32.667 回答
1

在 C++ 中,您通常会使用std::function它的 boost 等价物。然而,在某些情况下,有一个 C 风格的解决方案可能是合适的 - 即存储额外的用户数据并将其传递给函数。

typedef INT_PTR (*MsgHandlerFn)(WPARAM,LPARAM, void*);
struct MsgHandler
{
   MsgHandler( 
     MsgHandlerFn in_fn,
     void * in_user_data )
   : fn(in_fn), user_data(in_user_data)
   {}
   //TODO: Add copy constructor, assignment operator, default constructor
   MshHandlerFn fn;
   void * user_data;
};

class Dialog
{
protected:
    Dialog(void); // Must be inherited
    vector<MsgHandler> Handlers;
};

class CMainWnd : public Dialog
{
  public:
    INT_PTR MyHandler(WPARAM wp, LPARAM lp) {
        return TRUE;
    }
  protected:
    static INT_PTR MyHandlerStatic(WPARAM wp, LPARAM lp, void * user_data)
    {
       return static_cast<CMainWnd*>(user_data)->MyHandler(wp,lp);
    }
  public:
    CMainWnd(void) {
      Handlers.push_back( MsgHandler( &CMainWnd::MyHandlerStatic, this ) );
     }
};

现在,您的对话框调用处理程序的循环需要看起来更像这样

for( unsigned int i=0; i<Handlers.size(); ++i)
   Handlers[i].fn( wp,lp, Handlers[i].user_data);
于 2012-09-27T07:48:59.433 回答
0

这是一个描述您的问题的网页。

类成员函数只是不正常的函数。如果声明一个普通函数对你来说没问题(在示例中似乎没问题),那就这样做吧。

是派生类的成员,其构造函数是将它们添加到向量中的构造函数

如果你真的需要的话,你可以使用 ac 函数指针来使你的类的函数成员。我不知道你是否可以在类声明范围内声明一个非成员函数成员函数,如果可以的话,这样做。

祝你好运

于 2012-09-27T07:17:27.707 回答