2016-08-18 13 views
0

部分的に修飾された関数オブジェクトを別のスレッドで後で呼び出すことに問題があります。ポインタへのポインタとオブジェクトへのポインタの意味

GCCでは、マクロとtypedefを使用していますが、私は警告をクリアしようとしています。

「警告:条件付きサポートされているポインタ関数へのポインタとオブジェクト間のキャスト」の結果、以下のようなFunction_Castマクロ使用
#define Function_Cast(func_ref) (SubscriptionFunction*) func_ref 
typedef void(SubscriptionFunction(void*, std::shared_ptr<void>)); 

​​

を私は本当に必要なのはポインタであります私は標準を作ることができる::バインド<function_type>のオブジェクトです。これは通常どのように行われますか?

また、この条件付きでサポートされているものは本当に面倒です。私はx86上で私のコードがうまく動作することを知っていると私はこのsizeof(void *)== sizeof(this *)に依存することの限界を認識しています*。

また、コードがコンパイルされるようにデータポインタのような関数ポインタを扱う方法がありますか?私はそれがいかに悪いかを知ることに興味があります(もしそうであれば)。

関連するコードは:

#define Function_Cast(func_ref) (SubscriptionFunction*) func_ref 
typedef void(SubscriptionFunction(void*, std::shared_ptr<void>)); 
typedef void(CallTypeFunction(std::shared_ptr<void>)); 

Subscriber(void* owner, SubscriptionFunction* func, bool serialized = true) { 
    this->_owner = owner; 
    this->_serialized = serialized; 
    this->method = func; 

    call = std::bind(&Subscriber::_std_call, this, std::placeholders::_1); 
} 

void _std_call(std::shared_ptr<void> arg) { method(_owner, arg); } 
+2

非静的メンバ関数は、(メンバでない)関数への通常のポインタとして使用することはできません。あなたはC++ 11を持っていますが、['std :: function'](http://en.cppreference.com/w/cpp/utility/functional/function)と[' std :: bind'](http ://en.cppreference.com/w/cpp/utility/functional/bind)? –

+1

...またはlambdas? – lorro

+0

@JoachimPileborg私はstd :: functionを最初に使用しようとしましたが、これは主に名前のためですが、 'std :: function 'を 'std ::関数 'を呼び出すことで、同じ構造体にたくさん格納することができました。この変換に答えることも、その質問に対する答えになります。 –

答えて

0

ここでの問題は、関数の代わりにメンバー関数ポインタを使用しようとしているということですあなたが知っているので、それはしばしばfunction(this, ...)として実装されています。

struct S { 
    void f() {} 
}; 

using fn_ptr = void(*)(S*); 

void call(S* s, fn_ptr fn) 
{ 
    fn(s); 
    delete s; 
} 

int main() { 
    call(new S, (fn_ptr)&S::f); 
} 

http://ideone.com/fork/LJiohQ

しかし、それはおそらくないでしょう、これは実際に例(仮想関数)が働き、明らかにするという保証はありません。

メンバ関数は次のように渡されることが意図されている:

void call(S* s, void (S::*fn)()) 

と、次のように呼び出された:彼らはさまざまな種類をサポートしたいとき、人々はこれを回避する方法

(s->*fn)(); 

http://ideone.com/bJU5lx

メンバー以外の機能であるトランポリンを使用することです。

auto sub = new Subscriber(this, [](auto* s){ s->init(); }); 

か、あなたの呼び出しサイトで型の安全性をたい場合は、テンプレートコンストラクタ:

template<typename T> 
Subscriber(T* t, void(T::*fn)(), bool x); 

http://ideone.com/lECOp6

あなたは静的[メンバー]機能またはλのいずれかでこれを行うことができます

Subscriberコンストラクタが関数ポインタではなくstd::function<void(void))>を受け取る場合は、キャプチャラムダを渡して、void*

new Subscriber([this](){ init(); }, false); 
+0

私はこの理由を説明しているので、それはうまくいくはずです、なぜそれが時々動作するのですか、どのスタイルをリファクタリングしたいかによっていくつかの選択肢があります。 'std :: function'を使用するオーバーヘッドが実際の関数呼び出しよりもはるかに大きかったので、私はかなりのインラインアセンブリを作成しました。 –

0

それは通常、このような何かをやっています:

#include <functional> 
#include <memory> 

struct subscription 
{ 
    // RAII unsubscribe stuff in destructor here.... 
}; 

struct subscribable 
{ 
    subscription subscribe(std::function<void()> closure, std::weak_ptr<void> sentinel) 
    { 
    // perform the subscription 

    return subscription { 
     // some id so you can unsubscribe; 
    }; 
    } 


    // 
    // 

    void notify_subscriber(std::function<void()> const& closure, 
         std::weak_ptr<void> const & sentinel) 
    { 
    if (auto locked = sentinel.lock()) 
    { 
     closure(); 
    } 
    } 
}; 
関連する問題