2017-06-09 4 views
0

私はvoid*のCで1つのユースケースを考えていましたが、そのコードをC++に翻訳しようとしていました。これが問題であり、次はここでC++代替案void *への特定のケース

void callback(void* args) { 
    Something* something = static_cast<Something*>(args); 
    // use something 
} 

Something something; 
add_callback(callback, &something); 

いくつかのイベントは、引数何かで発生するたびにコールバックが呼び出されるためのソリューションです。 C++でこれをやって行くための慣用的な方法(あなたはそれが正しいではないと思う場合は、より良い解決策を見つける私を助ける)

Something something; 
add_callback([=something]() { 
    // do something 
}); 

、その後add_callback()次 ようなものになるだろうが、内部でラムダのタイプを消去するだろうし、時刻が来たら電話をかけるためにstd::function<>に保管してください。これより古いバージョンの利点は、コールバックがその状態をよりよくカプセル化することです。

しかし、これでわかった問題は、コールバックが呼び出されるたびに仮想関数ディスパッチの不要なオーバーヘッドが発生することです。 (仮定できるオーバーヘッドがなくても、私が好奇心を持っているだけなのでオーバーヘッドであると仮定します)、私が考えることができる唯一の解決策は、ここでstd::anyを使用することです(ただし、オブジェクトはコピーを構成可能にする必要があります)。 std::anyをメンバ変数として使用してコールバックを統一するか、またはstd::anyを関数(関数ポインタとして格納)に渡し、コールバックの状態のカプセル化を放棄します。しかし、何かもっと良い解決策があると私に伝えます...

+0

私が理解していないのは、コールバックが指すものが*常に*「何か」であれば、なぜ 'void *'となるのでしょうか?なぜ、「何か」を取ってみませんか? – Brian

+2

@Brian 'add_callback()'を提供するライブラリは、libevent – Curious

+0

@downvoterの 'event_new()'のようなことを知らないので、downvotingの理由を説明できますか? – Curious

答えて

0

C++で完全な型の使用を合理化するために関数テンプレートを使用できますが、static_castを避けることはできません。

例:

struct CallbackHandler 
{ 
    void doSomething() {} 
} 

template <typename T> 
void cpp_callback(T* args) 
{ 
    // Use args with full access to T. 
    args->doSomething(); 
} 

template <typename T> 
void callback(void* args) 
{ 
    cpp_callback(static_cast<T*>(args)); 
} 

int main() 
{ 
    add_callback(callback<CallbackHandler>, new CallbackHandler); 
} 
0

私はあなたが同時に型消去、型の安全性、ゼロオーバーヘッドのすべてを得ることができるとは思いません。

私が思いついた最高のは、このようなものです:

typedef void (*func_t)(void *p); 

template<typename T, void (T::*F)()> 
struct CB_helper 
{ 
    static void func(void *p) 
    { 
     T *t = static_cast<T*>(p); 
     (t->*F)(); 
    } 
}; 

template<typename T, void (T::*F)()> 
func_t CB() 
{ 
    return CB_helper<T, F>::func; 
} 

そしてあなたがそれを使用することができます:

struct Something 
{ 
    void do(); 
}; 
Something some; 
add_callback(CB<Something, &Something::do>(), &some); 

欠点あなたはそれぞれのタイプの新しいCB必要があるということですコールバックを使用する予定です。いくつかのスマートメタプログラミングを使って、引数の数ごとに1つのバージョンしか持たないようにすることができます。