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
  • 2 つのパラメーターを持ちます。最初のパラメーターは でWPARAM、2 番目のパラメーターは です。LPARAM
  • コンストラクターがそれらをベクターに追加するものである派生クラスのメンバーである

このようなことを行うために使用することを聞いたことがありboost::functionますが、ドキュメントを調べましたが、使用方法がわかりません。すべてが混乱しているようです。バインド操作などでコードを行き詰まらせるのではなく、変数であるかのように関数をベクトルに追加したいだけです。(ブースト機能に関しては、私が無知だからかもしれません)。

ここで何が間違っていますか、またはboost::functionこれを行うために使用できますか? boost::functionちなみにベクターを as と宣言して足し算vector<boost::function<INT_PTR(WPARAM,LPARAM)>>MyHandlerてみましたがだめでした。必要がない場合はブーストを使用したくないのですが、誰かがこれを行うブースト方法を提案している場合は、どうすればこれを行うことができるかを明確にしてください。

4

4 に答える 4

4

これは、C++11 にアクセスできる場合にラムダが真価を発揮する場所です。コードを少し変更するのは、コードを少し簡単に動作させることができるからですが、必要に応じて非常に簡単に修正できるはずです。

#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 を使用し、代わりにブーストする場合:

#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 に答える
4

次のことを考えてみてください: 関数ポインタのベクトルを作成するとき、ベクトルの各要素のサイズは? そうです、関数ポインタのサイズです。さて、関数へのポインターと、関数が呼び出されることになっているオブジェクトへのポインターを保持することをどのように期待できますか?

C++ 言語機能は、「使用した分だけ支払う」という原則に基づいて設計されています。そのため、関数ポインターは可能な限り軽量です。ここで、実際に必要なのはデリゲートです。デリゲートは C++ の言語機能ではないため、好むと好まざるとにかかわらず、boost::function などを使用する (または自分で作成する) 必要があります。ところで、boost::function よりも高速なデリゲート ソリューションがあります。確認できます:このコード プロジェクトこれ

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 に答える
1

C ++では、通常、std::functionまたはそれに相当するブーストを使用します。ただし、状況によっては適切な 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 に答える