2016-09-26 5 views
-1

のは、私は次の関数インタフェースを持っているとしましょう:単純に機能生の関数ポインタに近代的なC++ 11機能から変換

void giveme(void (*p)()); 

なし戻り値の型と引数を持つ関数へのポインタを受け付けます。

クラスメソッドをその関数のパラメータとして渡す方法があるかどうか(変更なしのインターフェイス

例を使って説明してみましょう。私は機能givemeのパラメータとして(クラスのアドレス可能なインスタンスの)bar<T>を渡したい

class Foo { 
public: 
    template<typename T> 
    void bar(); 
}; 

:ように私は、クラスを持っています。

私はバインドオブジェクトとメソッドを考え、関数のターゲットを取得すると思った。

int main(int argc, char *argv[]) { 
    Foo foo; 
    std::function<void()> f = std::bind(&Foo::bar<int>, &foo); 

    giveme(f.target<void()>()); 

    return 0; 
} 

それはコンパイルが、hereから、ので、明らかに動作しません:typeid(TargetType)==target_type()よう

TargetTypeは、ターゲット・タイプと一致するもののような

何か。それ以外の場合は、関数は常にnullポインタを返します。

これが実現する方法は何ですか?

Foo * foo_ptr; // maybe thread_local 

void foo_call() 
{ 
    foo_ptr->bar<int>(); 
} 

int main() 
{ 
    Foo foo; 
    foo_ptr = &foo; 
    give_me(&foo_call); 
} 

それはかなりありませんが、どちらもあなたの状況である:ここでは

+0

この特定の状態を維持する関数を作成するために、何らかのjitなしでこれを行うことはできません。 – krzaq

+4

短い答えは:いいえ、ありません。 –

+0

通常の方法はサンクですが、C++にはそのようなことはありません。 –

答えて

5

は1(非常に悪い)という考えです。

1

私が知っている唯一の方法はありますが、それはひどい考えです。これをしないでください。

typedef void (*void_fn)(); 
struct stateful_void_fn_data = { 
    void_fn raw; 
    std::function<void()> actual; 
    std::atomic_bool in_use; 
} 
// a global array to hold your function bindings and such 
extern stateful_void_fn_data stateful_functions[5]; 
// N stateless functions that defer to the correct global state 
template<int n> void void_fn_impl() {stateful_functions[n].actual();} 
extern stateful_void_fn_data stateful_functions[5] = 
    {{void_fn_impl<0>}, {void_fn_impl<1>}, {void_fn_impl<2>}, {void_fn_impl<3>}, {void_fn_impl<4>}}; 
// function to register a stateful and get a stateless back 
void_fn allocate_void_fn(std::function<void()>&& f) { 
    for(int i=0; i<5; i++) { 
     if(stateful_functions[i].in_use.compare_exchange_weak(false, true)) { 
      stateful_functions[i].actual = std::move(f); 
      return stateful_functions[i].raw; 
     } 
    } 
    throw std::runtime_error("ran out of stateful functions :("); 
} 
// function to unregister 
void free_void_fn(void_fn f) { 
    if (f == nullptr) return; 
    for(int i=0; i<5; i++) { 
     if (stateful_functions[i].raw == f) { 
      stateful_functions[i].in_use = false; 
      return; 
     } 
    } 
    throw std::runtime_error("unknown void function"); 
} 

基本的に、私は5つのvoid()機能(void_fn_impl<N>)を生成し、それぞれが5つのグローバル配列スロット(stateful_functions[i].actual)のいずれかに格納された関数を呼び出します。次に、allocate_void_fnはグローバル配列にstd::function<void()>を格納し、配列のその項目を呼び出すvoid()を渡します。この関数自体は、すべての状態をグローバル配列に格納しているため、ステートレスです。free_void_fnおよびin_useは、機能を再利用可能にするためだけに存在します。

そしてもちろん、RAIIが良いので:

class hidden_state_void_fn { 
    void_fn raw; 
public: 
    hidden_state_void_fn(std::function<void()>&& f) 
     :raw(allocate_void_fn(std::move(f)) {} 
    hidden_state_void_fn(const hidden_state_void_fn&& r) { 
     raw = r.raw; 
     r.raw = nullptr; 
    } 
    hidden_state_void_fn& operator=(const hidden_state_void_fn&& r) { 
     free_void_fn(raw); 
     raw = r.raw; 
     r.raw = nullptr; 
    } 
    ~hidden_state_void_fn() {free_void_fn(raw);} 
    operator void_fn() {return raw;} 
    operator()() {raw();} 
}; 
+0

'テンプレート void function(){stateful_functions [n] .actual();}少なくとも。 – Yakk

+0

'raw()'、 'actual(')を呼び出すと、どうやって動くのですか? ) 'が本当に呼び出されるのですか?少し遅れるかもしれませんが、私は実際にこの転送がここでどのように行われるのか見ていません。 –

+0

@FelixDombek:説明が追加されました。 –

0
std::map<int,std::function<void()>> tasks; 

template<int n> 
struct task_wrapper{ 
    static void f(){ if (tasks.count(n)) tasks[n](); } 
    task_wrapper(std::function<void()> fin){ tasks[n]=fin; } 
    ~task_wrapper(){ tasks.erase(n); } 
    static std::shared_ptr< void(*)() > make(std::function<void()> fin){ 
    auto self=std::make_shared<task_wrapper>(fin); 
    return { &f, fin }; 
    } 
}; 

Aは、ステートフルfuncを呼び出しますステートレス関数ポインタに共有ポインタを返すtask_wrapper<N>::make(func)

通常の技術を使用して、記号shared_ptr<void(*)()>(*)()のK関数ポインタの配列を作成できます。それから、shared_ptr<void(*)()> register_func(std::function<void()>)を持つことができます。

ブランクを見つけるには、線形検索を実行するか、空白のテーブルを作成します。これは、伝統的な割り当て/空きの "ヒープ"、またはブランクの範囲ツリー、またはそれと同じように見えるかもしれません。


もう1つの方法は、文字通りDLLを作成して保存し、ロードしてシンボルを呼び出すことです。これは、ハッキング(DLL、修正、コピー、書き込み、ロード、実行のためのDLLやオフセットを持っている)や、C++コンパイラ(または他のコンパイラ)をコード(!

関連する問題