2017-09-29 8 views
1

std :: functionとstd :: bindを使って遊んでみると、問題が発生しました。私は、メンバー関数の引数を先験的に知らなくても、メンバー関数にstd ::関数をバインドできる一般的な構造を構築したいと考えています。私はstd :: functionのアクセス違反がラムダに割り当てられました

template<typename Class, typename Return, typename ...Args> 
struct Caller 
{ 
private: 
    std::function<Return(Args ...)> callerFunction; 

    Caller(const Caller&) = delete; 
    Caller(Caller&&) = delete; 
    Caller& operator=(const Caller&) = delete; 

public: 
    ~Caller() = default; 
    Caller() = default; 

    Caller(Class& instance, Return(Class::*function)(Args...)) 
    { 
     callerFunction = [&](Args... args) { return (instance.*function)(args...); }; 
    } 

    Return operator() (Args ... args) 
    { 
     return callerFunction(args...); 
    } 
}; 

はFYI私は関数の引数は値によって渡されることを知っているこの事を書きました(私は可変長テンプレートユニバーサル参照を使用して、いくつかの問題が発生した、私は後に動作します)。

ここでの問題は、operator()で関数を起動するとアクセス違反エラーが発生することです。私は、問題を絞り込み、varadic引数を持たない構造体を作成しようとしました。(メンバ関数が引数としてintを持つことを可能にしています)、lddaをstd :: functionに代入するのは私に同じエラーが与えられていました。私はstd :: bindをプレースホルダと一緒に使っていましたが、すべてうまくいきました。

テスト地面はラムダを使用して、この

class A 
{ 
public: 
    bool foo(int a) 
    { 
     std::cout << a << std::endl; 
     return true; 
    } 
}; 

int main() 
{ 
    A a; 
    a.foo(9); 

    Caller<A, bool, int> caller(a, &A::foo); 
    caller(10); 

    std::cin.ignore(); 
} 

ですが、私は適切にメンバ関数を呼び出すために、クラスのインスタンスを保存する必要がありますか?

+1

私はあなたがUBを持っていると確信しています。 'Caller'のコンストラクタでは、メンバ関数のポインタを値で渡します(コンストラクタ内にのみ存在するポインタのコピーが作成されますが)。したがって、あなたが 'caller(10) 'を呼び出す時には、ポインタは範囲外です。 'instance'は、この例では、コンストラクタに参照渡しを渡し、' caller(10) 'を呼び出すときには' a'がスコープ内にあるので問題ありません。 (あなたはそれが将来変更され、その周りに設計されると仮定すべきですが) – 0x5453

+1

lambdaまたは 'std :: bind'でうまく動作する' std :: mem_fn'がすでに存在することにも注目する価値があります。 – 0x5453

+0

わかりました。私が理解できないことは、この問題をどのように修正できるかです。 インスタンスについて:プログラムの起動時に、いくつかのクラスがインスタンス化され、これらの変数はプログラムの最後まで使用可能になります。 – Astinog

答えて

1

コメントで述べているように、あなたがfunctionのダングリングポインタを持って、あなたの代わりに使用できます。

Caller(Class& instance, Return(Class::*function)(Args...)) 
{ 
    callerFunction = [&instance, function](Args... args) { 
     return (instance.*function)(std::forward<Args>(args)...); 
    }; 
} 

注:instanceCallerをoutlives必要があります。

0

[&]オブジェクトまたはそのコピーが現在のスコープを超えている場合は使用しないでください。

ローカル変数への参照をキャプチャし、現在のスコープを超えて保存しています。

関連する問題