C ++でwin32 APIラッパーを作成する際に、このポインターを静的関数に渡す方法

StackOverflow https://stackoverflow.com/questions/412183

  •  03-07-2019
  •  | 
  •  

質問

関数オブジェクトを関数に変換したい。

このコードを書きましたが、機能しません。

#include <iostream>

typedef int (*int_to_int)(int);

struct adder {
    int n_;
    adder (int n) : n_(n) {}
    int operator() (int x) { return x + n_; }
    operator int_to_int () {
        return this->*&adder::operator();
    }
};

int main(void) {
    adder add_two(2);
    int_to_int add_fn = add_two;
    std::cout << add_two(3) << std::endl; // expect 5
    std::cout << add_fn(3)  << std::endl; // expect 5
    add_fn = adder(5);
    std::cout << add_fn(3)  << std::endl; // expect 8
    return 0;
}

そしてg ++からメッセージを受け取ったと、非静的メンバー関数の無効な使用

インスタンスのメンバー関数へのポインターを取得するにはどうすればよいですか

編集:私の元々の問題はWin32 APIに関するものです。

学校で古いWin32 APIを使用してWindowsプログラムを作成する必要があります。しかし、テキストのコード例のように恐ろしいswitchステートメントを書きたくありません。それから、ラッパーをC ++で書くことにしました。

次のようにウィンドウクラスを記述したい

class Window {
public:
    LRESULT update (HWND, UINT, WPARAM, LPARAM);
    void run();
    // below methods are called by update()
    virtual void onclick(int, int);
    virtual void ondraw(); // ... and more methods
};

そして、このクラスを派生させ、いくつかのメソッドをオーバーロードして、アプリケーションクラスを作成します。

最後に、私の実際の問題は、C ++でこれを行う方法です。

 // on initializing my window object,
 // I must register window class with callback which is 
 // not a C++ function object.
 // I try to explain what I want to do with psudocode mixing C++ and javascript.
 WNDCLASS wndclass;
 Window *self = this;
 wndclass.lpfnWndProc = function () {
     return self.update.apply(self, argunemts);
 };

言い換えれば、クロージャーを関数ポインターにする必要があります。これを行う方法はわかりませんが、C ++ではできないとは思いません。

編集:この質問の元のタイトルは、インスタンスのメンバー関数へのポインターを取得する方法でした。しかし、このタイトルと私の質問は、実際の問題を十分に伝えていませんでした。初期の回答者、およびlitbにごめんなさい。提案と非常に有用な回答をありがとう!

役に立ちましたか?

解決

更新:あなたが欲しいものを教えてくれました。 SOでこの質問を見つけました:保存するための最良の方法WndProcで使用するためのこのポインタ。私はWindowsプログラマーではありませんが、Adam Rosenfield氏はSetWindowLongPtrとGetWindowLongPtrを使用するのに正しいようです。したがって、次のように使用します。

LRESULT CALLBACK my_callback(HWND hwnd, UINT ui, WPARAM wp, LPARAM lp) {
    Window * self = reinterpret_cast<Window*>(
        GetWindowLongPtr(hwnd, 0));
    return self->update(hwnd, ui, wp, lp); // handle it.
}

wnd-procとしてその関数を登録し、SetWindowLongPtrを使用してWindowオブジェクトの this ポインターを保存します。 WNDCLASSEX 構造体には、 sizeof(Window *)を割り当てる cbWndExtra フィールドがあります。ポインター。その後、呼び出すことができます

SetWindowLongPtr(my_hwnd, 0, reinterpret_cast<LONG_PTR>(this));

このポインタをその領域に配置します。次に、上記のように受け取り、実際のメンバー関数に委任します。理論的には、静的メンバー関数を使用することもできます。しかし、注意する必要があります。呼び出し規約がCコードとC ++コードで異なる可能性があるため、Cコードから静的メンバー関数を呼び出すとバグが発生する可能性があります。 Windowsの場合、それは問題ではないかもしれません-知りません。さらに自分自身を確認してください。


あなたが試みることは無効です。関数呼び出し演算子へのポインターを返そうとしましたが、変換演算子の型が間違っていることを除いて、呼び出しが行われたときにオブジェクトが提供されていません。変換演算子が返す型には関数ポインター型がありますが、メンバー関数ポインター型はありません。最も近い方法は、適切なタイプを使用することです:

struct adder;
typedef int (adder::*int_to_int)(int);

struct adder {
    int n_;
    adder (int n) : n_(n) {}
    int operator() (int x) { return x + n_; }
    operator int_to_int () {
        return &adder::operator();
    }
};

今、あなたの変換演算子は次のように呼び出されなければならないので、考慮されません:

adder a(10); cout << (a.*(int_to_int)a)(2); // expected: 12

そして手動で次のようにします:

// note, we just get the member function pointer using the conversion operator.
// Nothing is related to the actual temporary adder object. 
int_to_int i = adder(5);
cout << (adder(10).*i)(2); // expected: 12

通常の関数呼び出し構文はそれに対処しません。要するに、あなたがしようとすることは不可能です。

別の質問は、なぜそんなことをしたいのかと思います。元の問題が何であるかを知っているとき、私たちはあなたをより良く助けることができると思います。関数呼び出しのように見えて機能させようとしている場合、変換演算子はまったく必要ありません。

struct adder {
    int n_;
    adder (int n) : n_(n) {}
    int operator() (int x) { return x + n_; }
};

adder a(10); cout << a(2); // expected: 12

他のヒント

インスタンスメソッドポインターは少し注意が必要で、「通常の」関数ポインターとはまったく異なる獣です。

C ++ FAQ liteセクション33 それについて言わなければなりません。 this および具体例については

非静的メンバー関数へのポインターは、静的関数(またはグローバル、つまり静的関数)へのポインターとは異なります。パラメータ。

グローバルまたは静的の型は、int(*)(int)のようなものです

ただし、非静的の型はint(ClassName :: *)(int)のようなものです。

とはいえ、コンストラクターまたは構築されたオブジェクトを関数ポインターに割り当てようとしているように見えるため、コードには奇妙なものが含まれています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top