1

私は今、これに対する解決策を数日間探しています。残念ながら答えるのに十分な関連性のある質問は見つかりませんでした。ここに私の質問があります。次のコードを検討してください。

// dummy class A
class A {
public:
    void aFunction() { // <- this is the function I want to point at
        cout << "aFunction() is called\n";
    }
};

class B {
public:
    template <class Class> // get a function pointer
    void setFunction( void (Class::*func)() ) {
        p_func = func;
    }
    void (*p_func)(); // the function pointer
}

int main() {
    B obj;
    objb.setFunction(&A::aFunction);
    return 0;
}

にコンパイルエラーがありsetFunction()ますp_func = func;

'void(__thiscall A :: *)(void)'から'void(__cdecl *)(void)'に変換できません

そして、私はそれをどうにかして取り除くことができないようです。私はそれがそれらの目に見えないthisポインタ(__thiscall__cdecl)と関係があることを知っていますが、これらを処理する方法がわかりません。同じ構造になるようにメンバー変数p_funcもクラステンプレートにしようとしvoid (Class::*p_func)()ましたが(なぜ?)、1つのクラスに2つのクラステンプレートを含めることは違法であるように思われるため(なぜ?)、正しい解決策ではありません。今回、コンパイラは次のことについて不平を言います。

複数のテンプレートパラメータリストは許可されていません

このメソッド(テンプレートなし)はグローバル関数(現在使用している回避策)で完全に機能し、ライブラリ(sfgui)での使用を確認したので、完全に可能であるはずです。

なぜこれが必要なのかを理解するために、ボタンを作成しようとしています。このボタンは、私が望むどんな関数でも呼び出すことができるはずです。start()今のところ、作成しているアニメーションクラスの関数を呼び出したいと思います。

ps:実行できないので、この例は役に立たないことを知っていますp_func:関数は静的ではありません。それでもオブジェクトポインタ(setFunction( void (Class::*func)(), Class* ))を追加する必要がありますが、それは問題ではないようです。typedefそして、私は関数ポインタをより読みやすくすることを知っていますが、クラステンプレートではありません。


編集

さらに調査した結果、私はこの質問に対する答えではなく、別の質問に対する答えが必要だと思います。template <class Class>かつて、私は複数が実際に許可されていることに気づきました。ただし、コンパイラーは、どちらを使用する必要があるかをコンパイラーが認識できない可能性があるため、メンバー変数では許可されていません。これclassがエラーの原因である可能性があります。

複数のテンプレートパラメータリストは許可されていません

これは奇妙な説明です。とにかく助けてくれてありがとう、あなたは私にもっと良い洞察を与えてくれました。

4

2 に答える 2

3

Class::*funcメンバーへのポインターを通常の関数ポインターに変換することはできません。それらは異なるタイプです。

あなたはこれを回すべきです:

void (*p_func)(); // the function pointer

これに:

void (class::*p_func)(); // the function pointer

std::function<void()>を使用boost::bindしてバインドすることもできます。

std::function<void()> fun = boost::bind(class::member_fun, args);

編集

これを実行できるように、Bクラスをテンプレートにするのはどうですか。

#include<iostream>

class A {
public:
    void aFunction() { // <- this is the function I want to point at
        std::cout << "aFunction() is called\n";
    }
};

template<class T>
class B {
public:
    void setFunction( void (T::*func)() ) {
        p_func = func;
    }
    void (T::*p_func)(); // the function pointer
    void callfunc()
    {
       (t.*p_func)(); //call pointer to member
    }
   private:
   T t; 
};

int main() {
    B<A> obj;
    obj.setFunction(&A::aFunction);
    return 0;
}

実例

于 2013-03-11T18:51:26.730 に答える
0

ここで回答されているテンプレートや無効なポインタを使用せずに、不明なタイプのオブジェクトを保存する方法を探しているときに、完全な答えを自分で見つけました。特定の変換を可能にするダミーの親を作成する必要があるため、解決策は少し危険です。

アイデアは、親を作成し、ポイントすることが許可されているすべてのオブジェクトはそれから継承する必要があるということです。このようにして、複数のタイプのオブジェクトを保持できるポインタを作成できますParent *objが、もちろん、から継承するクラスのみParentです。

同じことが関数ポインタにも当てはまります。ポインターをvoid (Parent::*func)()メンバー変数として定義する場合。template <class Class> setFunction( void (Class::*f)() )任意のクラスへの任意のポインターを保持できるテンプレート関数ポインターをユーザーに求めることができます。Parent次に、関数ポインタを目的のクラス:にキャストする必要がありますstatic_cast<void(Parent::*)()>(f)。これは、クラスが親から継承する場合にのみ機能することに注意してください。そうしないと、コンパイルエラーが発生します。

最小限の作業例

#include <iostream>
using namespace std;

// dummy class Parent
class Parent {};

// class A
class A : public Parent { // Mind the inheritance!
public:
    A(int n) : num(n) {}

    void print() {  // <- function we want to point to
        cout << "Number: " << num << endl;
    }

    int num;
}

// class B, will hold the 2 pointers
class B {
public:
    B() {}

    template <class Class>  // will save the function and object pointer
    void setFunction( void (Class::*func)(), Class *obj) {
        function = static_cast<void(Parent::*)()>(func);
        object = obj;
    }

    void execFunction() {  // executes the function on the object
        (object->*function)();
    }

    void (Parent::*function)(); // the function pointer
    Parent *object;             // the object pointer
}

int main() {
    A a(5);
    B b;

    b.setFunction(&A::print, &a);
    b.execFunction();

    return 0;
}

私はこの解決策が本当に好きではありません。より良い解決策はB、関数を実行する必要があるときにブール値を返す関数を持つことができるということです。このようにして、目的の関数を実行する-functionにifステートメントを配置するだけで済みます。main

A a(5);
B b;
while (;;) {
    if (b.aTest())
        a.print();
}

B::aTest()として宣言されている場所

bool B::aTest();

これが同じ問題に遭遇した人に役立つことを願っています。したがって、それは完全に可能ですが、私の意見ではかなり危険です。最初の方法を使用する人はお勧めしません。

于 2013-03-12T12:34:19.607 に答える