3

私は現在、DonClugstonのfastdelegatesを使用してタイマー/コールバックシステムを実装しています。(http://www.codeproject.com/KB/cpp/FastDelegate.aspxを参照)

開始コードは次のとおりです。

struct TimerContext
{
};

void free_func( TimerContext* )
{
}

struct Foo
{
    void member_func( TimerContext* )
    {
    }
};

Foo f;
MulticastDelegate< void (TimerContext*) > delegate;

delegate += free_func;
delegate += bind( &Foo::member_func, &f );

さて、しかし今、私はユーザーがTimerContext自分の構造を保存してコールバックに送信するためにサブクラス化できることを望んでいます。ここでの目的は、ユーザーがTimerContext自分自身をダウンキャストする必要がないようにすることです。

struct TimerContext
{
};

struct MyTimerContext : TimerContext
{
    int user_value;
};

void free_func( TimerContext* )
{
}

void free_func2( MyTimerContext* )
{
}

struct Foo
{
    void member_func( TimerContext* )
    {
    }

    void member_func2( MyTimerContext* )
    {
    }
};

Foo f;
MulticastDelegate< void (TimerContext*) > delegate;

delegate += free_func;
delegate += free_func2;
delegate += bind( &Foo::member_func,  &f );
delegate += bind( &Foo::member_func2, &f );

ご想像のとおり、GCCは私にそれをさせません:)

error: invalid conversion from `void (*)(MyTimerContext*)' to `void (*)(TimerContext*)'
error:   initializing argument 1 of `delegate::Delegate<R ()(Param1)>::Delegate(R (*)(Param1)) [with R = void, Param1 = TimerContext*]'

だから今私の質問は:私がキャストを使用して強制するとreinterpret_cast、それは機能しますが、それは安全ですか?

PS:これらはタイムクリティカルなコールバックであり、重い仮想指向のソリューションは実行不可能と見なされます:/

4

3 に答える 3

5

C ++ Standardは、13.4/7で次のように述べています。

あるポインタから関数型への標準的な変換(4節)はありません。特に、Bの公的拠点であっDても、

D* f();
B* (*p1)() = &f;  // error
void g(D*);
void (*p2)(B*) = &g;  // error

それでも、関数アダプターを使用して、のような1つの引数で関数するポインターを格納することはできますが、それでboost::function問題が解決するかどうかは今のところわかりません。

于 2009-10-19T17:20:57.817 に答える
0

もちろん、関数ポインタをキャストすることは一般的に悪い考えです。

void(*)(Derived*)からへの関数ポインタのキャストは機能する場合と機能しvoid(*)(Base*)ない場合があります。変換時にDerived*およびBase*ポインターの内部表現を調整する必要がある場合は、確かに機能しません。ただし、単一の継承関係の場合、これは起こりそうにありません。それでも、クラスのレイアウトとポインターの調整は実装によって定義されるため、これに依存しないでください。リスクを冒したい場合:恐れ入ります。

ポインタを調整する必要がないと仮定すると、からvoid(*)(Derived1*)への変換void(*)(Base*)は、Derived1とDerived2が兄弟であるDerived2*でDerived1*が呼び出されることを期待する関数を許可するため、まだ良い考えではありません(タイプセーフではありません)。継承階層。

于 2009-10-19T17:22:20.580 に答える
0

reinterpret_castオブジェクトの「送信者」と「受信者」が対応する場合にのみ安全です。したがって、送信者と受信者が同じコードで実装されている場合、しばらくの間は非常に安全である可能性があります。

デリゲートにコールバックを追加する必要があり、コールバックに別のタイプを持たせたい場合は、次の2つのシナリオがあります

  • すべてのデリゲートを事前に知っているので、コンパイル時に=>タイプリストでそれらをラップできます。

  • デリゲートは実行時に構成できます=>ランタイムバインディング、つまり仮想関数(execメソッドなど)を使用する必要があります。

于 2009-10-19T17:27:37.697 に答える